Click here to Skip to main content
15,896,453 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 140.1K   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: 1965 $</version>
// </file>

using System;
using System.CodeDom;
using System.Collections;
using System.Collections.Generic;
using System.Text;

using ICSharpCode.NRefactory.Ast;

namespace ICSharpCode.NRefactory.Visitors
{
	public class CodeDomVisitor : AbstractAstVisitor
	{
		Stack<CodeNamespace>  namespaceDeclarations = new Stack<CodeNamespace>();
		Stack<CodeTypeDeclaration> typeDeclarations = new Stack<CodeTypeDeclaration>();
		Stack<CodeStatementCollection> codeStack    = new Stack<CodeStatementCollection>();
		List<CodeVariableDeclarationStatement> variables = new List<CodeVariableDeclarationStatement>();
        List<CodeParameterDeclarationExpression> parameters = new List<CodeParameterDeclarationExpression>();
        Stack<Breakable> breakableStack = new Stack<Breakable>();
		
		TypeDeclaration currentTypeDeclaration = null;
		
		IEnvironmentInformationProvider environmentInformationProvider = new DummyEnvironmentInformationProvider();

        // track break and continue statements
        class Breakable
        {
            public static int NextId = 0;

            public int Id = 0;
            public bool IsBreak = false;
            public bool IsContinue = false;
            public bool AllowContinue = true;

            public Breakable()
            {
                Id = ++NextId;
            }

            public Breakable(bool allowContinue)
                : this()
            {
                AllowContinue = allowContinue;
            }
        }

		public IEnvironmentInformationProvider EnvironmentInformationProvider {
			get {
				return environmentInformationProvider;
			}
			set {
				environmentInformationProvider = value;
			}
		}
		
		// dummy collection used to swallow statements
		CodeStatementCollection NullStmtCollection = new CodeStatementCollection();
		
		public CodeCompileUnit codeCompileUnit   = new CodeCompileUnit();

        // RG
        //
        // Initialise Scope Variables for Current Method
        void InitMethodScope()
        {
            usingId = 0;
            foreachId = 0;
            switchId = 0;
            doId = 0;
            Breakable.NextId = 0;
            variables.Clear();
            parameters.Clear();
        }

		CodeTypeReference ConvType(TypeReference type)
		{
			if (type == null) {
				throw new ArgumentNullException("type");
			}
			if (string.IsNullOrEmpty(type.SystemType)) {
				throw new InvalidOperationException("empty type");
			}
			
			CodeTypeReference t = new CodeTypeReference(type.SystemType);
			foreach (TypeReference gt in type.GenericTypes) {
				t.TypeArguments.Add(ConvType(gt));
			}
			if (type.IsArrayType) {
				t = new CodeTypeReference(t, type.RankSpecifier.Length);
			}
			
			return t;
		}
		
		void AddStmt(CodeStatement stmt)
		{
			if (codeStack.Count == 0)
				return;
			CodeStatementCollection stmtCollection = codeStack.Peek();
			if (stmtCollection != null) {
				stmtCollection.Add(stmt);
			}
		}
		
		// FIXME: map all modifiers correctly
		static MemberAttributes ConvMemberAttributes(Modifiers modifier)
		{
			MemberAttributes attr = (MemberAttributes)0;
			
			if ((modifier & Modifiers.Abstract) != 0)
				attr |=  MemberAttributes.Abstract;
			if ((modifier & Modifiers.Const) != 0)
				attr |=  MemberAttributes.Const;
			if ((modifier & Modifiers.Sealed) != 0)
				attr |=  MemberAttributes.Final;
			if ((modifier & Modifiers.New) != 0)
				attr |=  MemberAttributes.New;
			if ((modifier & Modifiers.Virtual) != 0)
				attr |=  MemberAttributes.Overloaded;
			if ((modifier & Modifiers.Override) != 0)
				attr |=  MemberAttributes.Override;
			if ((modifier & Modifiers.Static) != 0)
				attr |=  MemberAttributes.Static;
			
			if ((modifier & Modifiers.Public) != 0)
				attr |=  MemberAttributes.Public;
			else if ((modifier & Modifiers.Internal) != 0 && (modifier & Modifiers.Protected) != 0)
				attr |=  MemberAttributes.FamilyOrAssembly;
			else if ((modifier & Modifiers.Internal) != 0)
				attr |=  MemberAttributes.Assembly;
			else if ((modifier & Modifiers.Protected) != 0)
				attr |=  MemberAttributes.Family;
            else if ((modifier & Modifiers.Private) != 0)
                attr |= MemberAttributes.Private;
	
			return attr;
		}
		
		#region ICSharpCode.SharpRefactory.Parser.IASTVisitor interface implementation
		public override object VisitCompilationUnit(CompilationUnit compilationUnit, object data)
		{
			if (compilationUnit == null) {
				throw new ArgumentNullException("compilationUnit");
			}
            CodeNamespace globalNamespace = new CodeNamespace("Global");
            //namespaces.Add(globalNamespace);
			namespaceDeclarations.Push(globalNamespace);
			compilationUnit.AcceptChildren(this, data);
			codeCompileUnit.Namespaces.Add(globalNamespace);
			return globalNamespace;
		}
		
		public override object VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration, object data)
		{
			CodeNamespace currentNamespace = new CodeNamespace(namespaceDeclaration.Name);
			//namespaces.Add(currentNamespace);
			// add imports from mother namespace
			foreach (CodeNamespaceImport import in ((CodeNamespace)namespaceDeclarations.Peek()).Imports) {
				currentNamespace.Imports.Add(import);
			}
			namespaceDeclarations.Push(currentNamespace);
			namespaceDeclaration.AcceptChildren(this, data);
			namespaceDeclarations.Pop();
			codeCompileUnit.Namespaces.Add(currentNamespace);
			
			// TODO : Nested namespaces allowed in CodeDOM ? Doesn't seem so :(
			return null;
		}
		
		public override object VisitUsingDeclaration(UsingDeclaration usingDeclaration, object data)
		{
			foreach (Using u in usingDeclaration.Usings) {
				namespaceDeclarations.Peek().Imports.Add(new CodeNamespaceImport(u.Name));
			}
			return null;
		}

        // RG
        public override object VisitEventDeclaration(EventDeclaration eventDeclaration, object data)
        {
            CodeMemberEvent evt = new CodeMemberEvent();
            evt.Type = ConvType(eventDeclaration.TypeReference);
            evt.Name = eventDeclaration.Name;

            evt.Attributes = ConvMemberAttributes(eventDeclaration.Modifier);

            typeDeclarations.Peek().Members.Add(evt);

            return null;
        }
		
		public override object VisitAttributeSection(AttributeSection attributeSection, object data)
		{
			return null;
		}

        // RG: CodeTypeReferenceExpression
        public override object VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression, object data)
        {
            return new CodeTypeReferenceExpression(ConvType(typeReferenceExpression.TypeReference));
        }

		public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
		{
			TypeDeclaration oldTypeDeclaration = currentTypeDeclaration;
			this.currentTypeDeclaration = typeDeclaration;
			CodeTypeDeclaration codeTypeDeclaration = new CodeTypeDeclaration(typeDeclaration.Name);
			codeTypeDeclaration.IsClass     = typeDeclaration.Type == ClassType.Class;
			codeTypeDeclaration.IsEnum      = typeDeclaration.Type == ClassType.Enum;
			codeTypeDeclaration.IsInterface = typeDeclaration.Type == ClassType.Interface;
			codeTypeDeclaration.IsStruct    = typeDeclaration.Type == ClassType.Struct;
			
			if (typeDeclaration.BaseTypes != null) {
				foreach (TypeReference typeRef in typeDeclaration.BaseTypes) {
					codeTypeDeclaration.BaseTypes.Add(ConvType(typeRef));
				}
			}
			
			typeDeclarations.Push(codeTypeDeclaration);
			typeDeclaration.AcceptChildren(this, data);
			typeDeclarations.Pop();
			
			if (typeDeclarations.Count > 0) {
				typeDeclarations.Peek().Members.Add(codeTypeDeclaration);
			} else {
				namespaceDeclarations.Peek().Types.Add(codeTypeDeclaration);
			}
			currentTypeDeclaration = oldTypeDeclaration;
			
			return null;
		}
		
		public override object VisitDelegateDeclaration(DelegateDeclaration delegateDeclaration, object data)
		{
			CodeTypeDelegate codeTypeDelegate = new CodeTypeDelegate(delegateDeclaration.Name);
            codeTypeDelegate.Attributes = ConvMemberAttributes(delegateDeclaration.Modifier);
            codeTypeDelegate.ReturnType = ConvType(delegateDeclaration.ReturnType);

            foreach (ParameterDeclarationExpression parameter in delegateDeclaration.Parameters)
            {
                codeTypeDelegate.Parameters.Add((CodeParameterDeclarationExpression)VisitParameterDeclarationExpression(parameter, data));
            }

            if (typeDeclarations.Count > 0)
            {
                typeDeclarations.Peek().Members.Add(codeTypeDelegate);
            }
            else
            {
                namespaceDeclarations.Peek().Types.Add(codeTypeDelegate);
            }

			return null;
		}
		
		public override object VisitVariableDeclaration(VariableDeclaration variableDeclaration, object data)
		{
			return null;
		}
		
		public override object VisitFieldDeclaration(FieldDeclaration fieldDeclaration, object data)
		{
			for (int i = 0; i < fieldDeclaration.Fields.Count; ++i) {
				VariableDeclaration field = (VariableDeclaration)fieldDeclaration.Fields[i];
				
				if ((fieldDeclaration.Modifier & Modifiers.WithEvents) != 0) {
					//this.withEventsFields.Add(field);
				}
				TypeReference fieldType = fieldDeclaration.GetTypeForField(i);
				
				if (fieldType.IsNull) {
					fieldType = new TypeReference(typeDeclarations.Peek().Name);
				}
				
				CodeMemberField memberField = new CodeMemberField(ConvType(fieldType), field.Name);
				memberField.Attributes = ConvMemberAttributes(fieldDeclaration.Modifier);
				if (!field.Initializer.IsNull) {
					memberField.InitExpression = (CodeExpression)field.Initializer.AcceptVisitor(this, data);
				}
				
				typeDeclarations.Peek().Members.Add(memberField);
			}
			
			return null;
		}
		
		public override object VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data)
		{
            InitMethodScope();

			CodeMemberMethod memberMethod = new CodeMemberMethod();
			memberMethod.Name = methodDeclaration.Name;
			memberMethod.Attributes = ConvMemberAttributes(methodDeclaration.Modifier);

            // RG: Private Interface Decl
            if ((memberMethod.Attributes & MemberAttributes.Public) != MemberAttributes.Public &&
                methodDeclaration.InterfaceImplementations.Count > 0) 
            {
                memberMethod.PrivateImplementationType = ConvType(methodDeclaration.InterfaceImplementations[0].InterfaceType);
            }

			codeStack.Push(memberMethod.Statements);
			
			typeDeclarations.Peek().Members.Add(memberMethod);
			
			// Add Method Parameters
            parameters.Clear();

			foreach (ParameterDeclarationExpression parameter in methodDeclaration.Parameters)
			{
				memberMethod.Parameters.Add((CodeParameterDeclarationExpression)VisitParameterDeclarationExpression(parameter, data));
			}

            usingId = 0; // RG
            foreachId = 0;
            switchId = 0;
            doId = 0;
            Breakable.NextId = 0;
			variables.Clear();
			methodDeclaration.Body.AcceptChildren(this, data);
			
			codeStack.Pop();
			
			return null;
		}

        // RG
        public override object VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration, object data)
        {
            CodeMemberProperty memberProperty = new CodeMemberProperty();
            memberProperty.Name = propertyDeclaration.Name;
            memberProperty.Attributes = ConvMemberAttributes(propertyDeclaration.Modifier);
            memberProperty.HasGet = propertyDeclaration.HasGetRegion;
            memberProperty.HasSet = propertyDeclaration.HasSetRegion;
            memberProperty.Type = ConvType(propertyDeclaration.TypeReference);

            typeDeclarations.Peek().Members.Add(memberProperty);

            // Add Method Parameters
            foreach (ParameterDeclarationExpression parameter in propertyDeclaration.Parameters)
            {
                memberProperty.Parameters.Add((CodeParameterDeclarationExpression)VisitParameterDeclarationExpression(parameter, data));
            }

            if (memberProperty.HasGet)
            {
                codeStack.Push(memberProperty.GetStatements);
                propertyDeclaration.GetRegion.Block.AcceptChildren(this, data);
                codeStack.Pop();
            }

            if (memberProperty.HasSet)
            {
                codeStack.Push(memberProperty.SetStatements);
                propertyDeclaration.SetRegion.Block.AcceptChildren(this, data);
                codeStack.Pop();
            }

            return null;
        }
		
		public override object VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data)
		{
            InitMethodScope();

			CodeConstructor memberMethod = new CodeConstructor();
            memberMethod.Attributes = ConvMemberAttributes(constructorDeclaration.Modifier);

			typeDeclarations.Peek().Members.Add(memberMethod);

            codeStack.Push(NullStmtCollection);
            foreach (ParameterDeclarationExpression parameter in constructorDeclaration.Parameters)
            {
                memberMethod.Parameters.Add((CodeParameterDeclarationExpression)VisitParameterDeclarationExpression(parameter, data));
            }
            
            if (constructorDeclaration.ConstructorInitializer != null)
            {
                if (constructorDeclaration.ConstructorInitializer.ConstructorInitializerType == ConstructorInitializerType.Base)
                {
                    if (constructorDeclaration.ConstructorInitializer.Arguments.Count == 0)
                    {
                        memberMethod.BaseConstructorArgs.Add(new CodeSnippetExpression());
                    }
                    
                    foreach (Expression o in constructorDeclaration.ConstructorInitializer.Arguments)
                    {
                        memberMethod.BaseConstructorArgs.Add((CodeExpression)o.AcceptVisitor(this, data));
                    }
                }

                if (constructorDeclaration.ConstructorInitializer.ConstructorInitializerType == ConstructorInitializerType.This)
                {
                    if (constructorDeclaration.ConstructorInitializer.Arguments.Count == 0)
                    {
                        memberMethod.ChainedConstructorArgs.Add(new CodeSnippetExpression());
                    }

                    foreach (Expression o in constructorDeclaration.ConstructorInitializer.Arguments)
                    {
                        memberMethod.ChainedConstructorArgs.Add((CodeExpression)o.AcceptVisitor(this, data));
                    }
                }
            }
            codeStack.Pop();

            codeStack.Push(memberMethod.Statements);
            constructorDeclaration.Body.AcceptChildren(this, data);
			codeStack.Pop();
			
			return null;
		}

		public override object VisitBlockStatement(BlockStatement blockStatement, object data)
		{
			blockStatement.AcceptChildren(this, data);
			return null;
		}
		
		public override object VisitExpressionStatement(ExpressionStatement expressionStatement, object data)
		{
			object exp = expressionStatement.Expression.AcceptVisitor(this, data);
			if (exp is CodeExpression) {
				AddStmt(new CodeExpressionStatement((CodeExpression)exp));
			}
			return exp;
		}
		
		public override object VisitLocalVariableDeclaration(LocalVariableDeclaration localVariableDeclaration, object data)
		{
			CodeVariableDeclarationStatement declStmt = null;
			
			for (int i = 0; i < localVariableDeclaration.Variables.Count; ++i) {
				CodeTypeReference type = ConvType(localVariableDeclaration.GetTypeForVariable(i) ?? new TypeReference("object"));
				VariableDeclaration var = (VariableDeclaration)localVariableDeclaration.Variables[i];
				if (!var.Initializer.IsNull) {
					declStmt = new CodeVariableDeclarationStatement(type,
					                                                var.Name,
					                                                (CodeExpression)((INode)var.Initializer).AcceptVisitor(this, data));
				} else {
					declStmt = new CodeVariableDeclarationStatement(type,
					                                                var.Name);
				}
				variables.Add(declStmt);
				AddStmt(declStmt);
			}
			
			return declStmt;
		}
		
		public override object VisitEmptyStatement(EmptyStatement emptyStatement, object data)
		{
			CodeSnippetStatement emptyStmt = new CodeSnippetStatement();
			
			AddStmt(emptyStmt);
			
			return emptyStmt;
		}
		
		public override object VisitReturnStatement(ReturnStatement returnStatement, object data)
		{
			CodeMethodReturnStatement returnStmt;
			if (returnStatement.Expression.IsNull)
				returnStmt = new CodeMethodReturnStatement();
			else
				returnStmt = new CodeMethodReturnStatement((CodeExpression)returnStatement.Expression.AcceptVisitor(this,data));
			
			AddStmt(returnStmt);
			
			return returnStmt;
		}
		
		public override object VisitIfElseStatement(IfElseStatement ifElseStatement, object data)
		{
			CodeConditionStatement ifStmt = new CodeConditionStatement();
			
			ifStmt.Condition = (CodeExpression)ifElseStatement.Condition.AcceptVisitor(this, data);
			
			codeStack.Push(ifStmt.TrueStatements);
			foreach (Statement stmt in ifElseStatement.TrueStatement) {
				if (stmt is BlockStatement) {
					stmt.AcceptChildren(this, data);
				} else {
					stmt.AcceptVisitor(this, data);
				}
			}
			codeStack.Pop();
			
			codeStack.Push(ifStmt.FalseStatements);
			foreach (Statement stmt in ifElseStatement.FalseStatement) {
				if (stmt is BlockStatement) {
					stmt.AcceptChildren(this, data);
				} else {
					stmt.AcceptVisitor(this, data);
				}
			}
			codeStack.Pop();
			
			AddStmt(ifStmt);
			
			return ifStmt;
		}

        int foreachId = 0; // in case of nested foreach statments

        public override object VisitForeachStatement(ForeachStatement foreachStatement, object data)
        {
            // RG:
            //  foreach (T t in x)
            //  {
            //      stmts;
            //  }
            //
            // Emulate with
            //
            //  for (System.Collections.IEnumerator _it = x.GetEnumerator(); _it.MoveNext(); )
            //  {
            //      T t = ((T)_it.Current);
            //
            //      stmts;
            //  }

            foreachId++;
            string name = "_it" + foreachId.ToString();

            CodeIterationStatement _for1 = new CodeIterationStatement();
            breakableStack.Push(new Breakable());

            // init
            CodeVariableDeclarationStatement _decl2 = new CodeVariableDeclarationStatement();
            CodeMethodInvokeExpression _invoke1 = new CodeMethodInvokeExpression();
            CodeMethodReferenceExpression _GetEnumerator_method1 = new CodeMethodReferenceExpression();
            _GetEnumerator_method1.MethodName = "GetEnumerator";
            
            //CodeCastExpression _cast1 = new CodeCastExpression();
            //codeStack.Push(NullStmtCollection);
            //_cast1.Expression = (CodeExpression)foreachStatement.Expression.AcceptVisitor(this, data);
            //codeStack.Pop();
            //CodeTypeReference _IEnumerable_type1 = new CodeTypeReference("System.Collections.IEnumerable");
            //_cast1.TargetType = _IEnumerable_type1;

            //_GetEnumerator_method1.TargetObject = _cast1;

            codeStack.Push(NullStmtCollection);
            _GetEnumerator_method1.TargetObject = (CodeExpression)foreachStatement.Expression.AcceptVisitor(this, data);
            codeStack.Pop();

            _invoke1.Method = _GetEnumerator_method1;
            _decl2.InitExpression = _invoke1;
            _decl2.Name = name;
            CodeTypeReference _IEnumerator_type1 = new CodeTypeReference("System.Collections.IEnumerator");
            _decl2.Type = _IEnumerator_type1;
            _for1.InitStatement = _decl2;

            // Condition
            CodeMethodInvokeExpression _invoke2 = new CodeMethodInvokeExpression();
            CodeMethodReferenceExpression _MoveNext_method1 = new CodeMethodReferenceExpression();
            _MoveNext_method1.MethodName = "MoveNext";
            CodeVariableReferenceExpression _arg2 = new CodeVariableReferenceExpression();
            _arg2.VariableName = name;
            _MoveNext_method1.TargetObject = _arg2;
            _invoke2.Method = _MoveNext_method1;
            _for1.TestExpression = _invoke2;

            // Empty Increment
            _for1.IncrementStatement = new CodeExpressionStatement(new CodeSnippetExpression());

            // T t = ((T)_it.Current);
            CodeVariableDeclarationStatement _decl3 = new CodeVariableDeclarationStatement();
            CodeCastExpression _cast2 = new CodeCastExpression();
            CodePropertyReferenceExpression _prop1 = new CodePropertyReferenceExpression();
            _prop1.PropertyName = "Current";
            CodeVariableReferenceExpression _arg3 = new CodeVariableReferenceExpression();
            _arg3.VariableName = name;
            _prop1.TargetObject = _arg3;
            _cast2.Expression = _prop1;
            CodeTypeReference _System_String_type5 = ConvType(foreachStatement.TypeReference);
            _cast2.TargetType = _System_String_type5;
            _decl3.InitExpression = _cast2;
            _decl3.Name = foreachStatement.VariableName;
            CodeTypeReference _System_String_type6 = ConvType(foreachStatement.TypeReference);
            _decl3.Type = _System_String_type6;
            _for1.Statements.Add(_decl3);
            _for1.Statements.Add(new CodeSnippetStatement());

            codeStack.Push(_for1.Statements);
            foreachStatement.EmbeddedStatement.AcceptVisitor(this, data);
            codeStack.Pop();

            Breakable breakable = breakableStack.Pop();

            if (breakable.IsContinue)
            {
                _for1.Statements.Add(new CodeSnippetStatement());
                _for1.Statements.Add(new CodeLabeledStatement("continue" + breakable.Id, new CodeExpressionStatement(new CodeSnippetExpression())));
            }

            AddStmt(_for1);

            if (breakable.IsBreak)
            {
                AddStmt(new CodeLabeledStatement("break" + breakable.Id, new CodeExpressionStatement(new CodeSnippetExpression())));
            }

            return _for1;
        }

        int doId = 0;

        // RG:
        public override object VisitDoLoopStatement(DoLoopStatement doLoopStatement, object data)
        {
            CodeIterationStatement forLoop = new CodeIterationStatement();
            breakableStack.Push(new Breakable());

            codeStack.Push(NullStmtCollection);

            if (doLoopStatement.ConditionPosition == ConditionPosition.End)
            {
                // do { } while (expr);
                //
                // emulate with:
                //  for (bool _do = true; _do; _do = expr) {}
                //
                doId++;
                string name = "_do" + doId;

                forLoop.InitStatement = new CodeVariableDeclarationStatement(typeof(System.Boolean), name, new CodePrimitiveExpression(true));
                forLoop.TestExpression = new CodeVariableReferenceExpression(name);

                forLoop.IncrementStatement = new CodeAssignStatement(new CodeVariableReferenceExpression(name),
                    doLoopStatement.Condition == null ? new CodePrimitiveExpression(true) : (CodeExpression)doLoopStatement.Condition.AcceptVisitor(this, data));
            }
            else
            {
                // while (expr) {}
                //
                // emulate with:
                //  for (; expr;) {}
                //

                // Empty Init and Increment Statements
                forLoop.InitStatement = new CodeExpressionStatement(new CodeSnippetExpression());
                forLoop.IncrementStatement = new CodeExpressionStatement(new CodeSnippetExpression());

                if (doLoopStatement.Condition == null)
                {
                    forLoop.TestExpression = new CodePrimitiveExpression(true);
                }
                else
                {
                    forLoop.TestExpression = (CodeExpression)doLoopStatement.Condition.AcceptVisitor(this, data);
                }
            }

            codeStack.Pop();

            codeStack.Push(forLoop.Statements);
            doLoopStatement.EmbeddedStatement.AcceptVisitor(this, data);
            codeStack.Pop();

            if (forLoop.Statements.Count == 0)
            {
                forLoop.Statements.Add(new CodeSnippetStatement());
            }

            Breakable breakable = breakableStack.Pop();

            if (breakable.IsContinue)
            {
                forLoop.Statements.Add(new CodeSnippetStatement());
                forLoop.Statements.Add(new CodeLabeledStatement("continue" + breakable.Id, new CodeExpressionStatement(new CodeSnippetExpression())));
            }

            AddStmt(forLoop);

            if (breakable.IsBreak)
            {
                AddStmt(new CodeLabeledStatement("break" + breakable.Id, new CodeExpressionStatement(new CodeSnippetExpression())));
            }

            return forLoop;
        }

		public override object VisitForStatement(ForStatement forStatement, object data)
		{
			CodeIterationStatement forLoop = new CodeIterationStatement();
            breakableStack.Push(new Breakable());

            codeStack.Push(NullStmtCollection);

            if (forStatement.Initializers.Count > 0)
            {
                if (forStatement.Initializers.Count > 1)
                {
                    throw new NotSupportedException("CodeDom does not support Multiple For-Loop Initializer Statements");
                }

                foreach (object o in forStatement.Initializers)
                {
                    if (o is Expression)
                    {
                        forLoop.InitStatement = new CodeExpressionStatement((CodeExpression)((Expression)o).AcceptVisitor(this, data));
                    }
                    if (o is Statement)
                    {
                        forLoop.InitStatement = (CodeStatement)((Statement)o).AcceptVisitor(this, data);
                    }
                }
            }
            else
            {
                // RG: need to handle empty InitStatement
                forLoop.InitStatement = new CodeExpressionStatement(new CodeSnippetExpression());
            }
			
			if (forStatement.Condition == null) {
				forLoop.TestExpression = new CodePrimitiveExpression(true);
			} else {
				forLoop.TestExpression = (CodeExpression)forStatement.Condition.AcceptVisitor(this, data);
			}
			
			codeStack.Push(forLoop.Statements);
			forStatement.EmbeddedStatement.AcceptVisitor(this, data);
			codeStack.Pop();

            if (forStatement.Iterator.Count > 0)
            {
                if (forStatement.Initializers.Count > 1)
                {
                    throw new NotSupportedException("CodeDom does not support Multiple For-Loop Iterator Statements");
                }

                foreach (Statement stmt in forStatement.Iterator)
                {
                    forLoop.IncrementStatement = (CodeStatement)stmt.AcceptVisitor(this, data);
                }
            }
            else
            {
                // RG: need to handle empty IncrementStatement
                forLoop.IncrementStatement = new CodeExpressionStatement(new CodeSnippetExpression());
            }

            codeStack.Pop();

            Breakable breakable = breakableStack.Pop();

            if (breakable.IsContinue)
            {
                forLoop.Statements.Add(new CodeSnippetStatement());
                forLoop.Statements.Add(new CodeLabeledStatement("continue" + breakable.Id, new CodeExpressionStatement(new CodeSnippetExpression())));
            }

			AddStmt(forLoop);

            if (breakable.IsBreak)
            {
                AddStmt(new CodeLabeledStatement("break" + breakable.Id, new CodeExpressionStatement(new CodeSnippetExpression())));
            }
	
			return forLoop;
		}
		
		public override object VisitLabelStatement(LabelStatement labelStatement, object data)
		{
			System.CodeDom.CodeLabeledStatement labelStmt = new CodeLabeledStatement(labelStatement.Label,(CodeStatement)labelStatement.AcceptVisitor(this, data));
			
			// Add Statement to Current Statement Collection
			AddStmt(labelStmt);
			
			return labelStmt;
		}
		
		public override object VisitGotoStatement(GotoStatement gotoStatement, object data)
		{
			System.CodeDom.CodeGotoStatement gotoStmt = new CodeGotoStatement(gotoStatement.Label);
			
			// Add Statement to Current Statement Collection
			AddStmt(gotoStmt);
			
			return gotoStmt;
		}

        // RG
        int switchId = 0;

		public override object VisitSwitchStatement(SwitchStatement switchStatement, object data)
		{
            // switch(arg) { case label1: expr1; case label2: expr2; default: expr3; }
            //
            // Emulate With:
            // 
            //  object _switch1 = arg;
            //  if (arg.Equals(label1))
            //  {
            //      expr1;
            //  }
            //  else
            //  {
            //      if (arg.Equals(label2))
            //      {
            //          expr2;
            //      }
            //      else
            //      {
            //          expr3;
            //      }
            //  }
            //

            switchId++; // in case nested switch() statements
            string name = "_switch" + switchId.ToString();

            breakableStack.Push(new Breakable(false));

            bool isSwitchArg = false;

            CodeVariableReferenceExpression switchArg = null;
            SwitchSection defaultSection = null;

            // get default section
            foreach (SwitchSection section in switchStatement.SwitchSections)
            {
                foreach (CaseLabel label in section.SwitchLabels)
                {
                    if (label.IsDefault)
                    {
                        defaultSection = section;
                        break;
                    }
                }

                if (defaultSection != null)
                    break;
            }


            CodeConditionStatement _if = null;

            // get default section
            foreach (SwitchSection section in switchStatement.SwitchSections)
            {
                if (section != defaultSection)
                {
                    if (!isSwitchArg)
                    {
                        isSwitchArg = true;

                        codeStack.Push(NullStmtCollection);
                        CodeVariableDeclarationStatement switchStmt = new CodeVariableDeclarationStatement("System.Object", name, (CodeExpression)switchStatement.SwitchExpression.AcceptVisitor(this, data));
                        codeStack.Pop();

                        switchArg = new CodeVariableReferenceExpression(name);

                        AddStmt(switchStmt);
                        AddStmt(new CodeSnippetStatement());
                    }

                    codeStack.Push(NullStmtCollection);

                    CodeExpression condition = null;
                    foreach (CaseLabel label in section.SwitchLabels)
                    {
                        CodeMethodInvokeExpression cond = new CodeMethodInvokeExpression(switchArg, "Equals", (CodeExpression)label.Label.AcceptVisitor(this, data));
                        if (condition == null)
                        {
                            condition = cond;
                        }
                        else
                        {
                            condition = new CodeBinaryOperatorExpression(condition, CodeBinaryOperatorType.BooleanOr, cond);
                        }
                    }

                    codeStack.Pop();

                    if (_if == null)
                    {
                        _if = new CodeConditionStatement();
                        _if.Condition = condition;

                        AddStmt(_if);
                    }
                    else
                    {
                        CodeConditionStatement _if2 = new CodeConditionStatement();
                        _if2.Condition = condition;

                        _if.FalseStatements.Add(_if2);

                        _if = _if2;
                    }

                    codeStack.Push(_if.TrueStatements);

                    for (int i = 0; i < section.Children.Count; i++)
                    {
                        INode stmt = section.Children[i];

                        if (i == section.Children.Count - 1 && stmt is BreakStatement)
                            break;

                        stmt.AcceptVisitor(this, data);
                    }

                    codeStack.Pop();
                }
            }

            if (defaultSection != null)
            {
                if (_if != null)
                    codeStack.Push(_if.FalseStatements);

                for (int i = 0; i < defaultSection.Children.Count; i++)
                {
                    INode stmt = defaultSection.Children[i];

                    if (i == defaultSection.Children.Count - 1 && stmt is BreakStatement)
                        break;

                    stmt.AcceptVisitor(this, data);
                }

                if (_if != null)
                    codeStack.Pop();
            }

            Breakable breakable = breakableStack.Pop();

            if (breakable.IsContinue)
            {
                throw new Exception("Continue Inside Switch Not Supported");
            }

            if (breakable.IsBreak)
            {
                AddStmt(new CodeLabeledStatement("break" + breakable.Id, new CodeExpressionStatement(new CodeSnippetExpression())));
            }

            return null;
		}
		
		public override object VisitTryCatchStatement(TryCatchStatement tryCatchStatement, object data)
		{
			// add a try-catch-finally
			CodeTryCatchFinallyStatement tryStmt = new CodeTryCatchFinallyStatement();
			
			codeStack.Push(tryStmt.TryStatements);
			
			tryCatchStatement.StatementBlock.AcceptChildren(this, data);
			codeStack.Pop();
			
			if (!tryCatchStatement.FinallyBlock.IsNull) {
				codeStack.Push(tryStmt.FinallyStatements);
				
				tryCatchStatement.FinallyBlock.AcceptChildren(this,data);
				codeStack.Pop();
			}
			
			foreach (CatchClause clause in tryCatchStatement.CatchClauses)
			{
				CodeCatchClause catchClause = new CodeCatchClause(clause.VariableName);
				catchClause.CatchExceptionType = ConvType(clause.TypeReference);
				tryStmt.CatchClauses.Add(catchClause);
				
				codeStack.Push(catchClause.Statements);
				
				clause.StatementBlock.AcceptChildren(this, data);
				codeStack.Pop();
			}
			
			// Add Statement to Current Statement Collection
			AddStmt(tryStmt);
			
			return tryStmt;
		}
		
		public override object VisitThrowStatement(ThrowStatement throwStatement, object data)
		{
			CodeThrowExceptionStatement throwStmt = new CodeThrowExceptionStatement((CodeExpression)throwStatement.Expression.AcceptVisitor(this, data));
			
			// Add Statement to Current Statement Collection
			AddStmt(throwStmt);
			
			return throwStmt;
		}
		
		public override object VisitFixedStatement(FixedStatement fixedStatement, object data)
		{
			throw new NotSupportedException("CodeDom does not support Fixed Statement");
		}
		
		#region Expressions
		public override object VisitPrimitiveExpression(PrimitiveExpression primitiveExpression, object data)
		{
			return new CodePrimitiveExpression(primitiveExpression.Value);
		}
		
		public override object VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, object data)
		{
			CodeBinaryOperatorType op = CodeBinaryOperatorType.Add;
			switch (binaryOperatorExpression.Op) {
				case BinaryOperatorType.Add:
					op = CodeBinaryOperatorType.Add;
					break;
				case BinaryOperatorType.BitwiseAnd:
					op = CodeBinaryOperatorType.BitwiseAnd;
					break;
				case BinaryOperatorType.BitwiseOr:
					op = CodeBinaryOperatorType.BitwiseOr;
					break;
				case BinaryOperatorType.LogicalAnd:
					op = CodeBinaryOperatorType.BooleanAnd;
					break;
				case BinaryOperatorType.LogicalOr:
					op = CodeBinaryOperatorType.BooleanOr;
					break;
				case BinaryOperatorType.Divide:
				case BinaryOperatorType.DivideInteger:
					op = CodeBinaryOperatorType.Divide;
					break;
				case BinaryOperatorType.GreaterThan:
					op = CodeBinaryOperatorType.GreaterThan;
					break;
				case BinaryOperatorType.GreaterThanOrEqual:
					op = CodeBinaryOperatorType.GreaterThanOrEqual;
					break;
				case BinaryOperatorType.Equality:
					op = CodeBinaryOperatorType.IdentityEquality;
					break;
				case BinaryOperatorType.InEquality:
					op = CodeBinaryOperatorType.IdentityInequality;
					break;
				case BinaryOperatorType.LessThan:
					op = CodeBinaryOperatorType.LessThan;
					break;
				case BinaryOperatorType.LessThanOrEqual:
					op = CodeBinaryOperatorType.LessThanOrEqual;
					break;
				case BinaryOperatorType.Modulus:
					op = CodeBinaryOperatorType.Modulus;
					break;
				case BinaryOperatorType.Multiply:
					op = CodeBinaryOperatorType.Multiply;
					break;
				case BinaryOperatorType.Subtract:
					op = CodeBinaryOperatorType.Subtract;
					break;
					//case BinaryOperatorType.ValueEquality:
					//	op = CodeBinaryOperatorType.ValueEquality;
					//	break;
				case BinaryOperatorType.ShiftLeft:
				case BinaryOperatorType.ShiftRight:
					// CodeDOM suxx
					op = CodeBinaryOperatorType.Multiply;
					break;
				case BinaryOperatorType.ReferenceEquality:
					op = CodeBinaryOperatorType.IdentityEquality;
					break;
				case BinaryOperatorType.ReferenceInequality:
					op = CodeBinaryOperatorType.IdentityInequality;
					break;
					
				case BinaryOperatorType.ExclusiveOr:
					// TODO ExclusiveOr
					op = CodeBinaryOperatorType.BitwiseAnd;
					break;
			}

            System.Diagnostics.Debug.Assert(!binaryOperatorExpression.Left.IsNull);
            System.Diagnostics.Debug.Assert(!binaryOperatorExpression.Right.IsNull);

			return new CodeBinaryOperatorExpression((CodeExpression)binaryOperatorExpression.Left.AcceptVisitor(this, data),
			                                        op,
			                                        (CodeExpression)binaryOperatorExpression.Right.AcceptVisitor(this, data));
		}
		
		public override object VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression, object data)
		{
			return parenthesizedExpression.Expression.AcceptVisitor(this, data);
		}
		
		public override object VisitInvocationExpression(InvocationExpression invocationExpression, object data)
		{
			Expression     target     = invocationExpression.TargetObject;
			CodeExpression targetExpr;
			string         methodName = null;
			if (target == null) {
				targetExpr = new CodeThisReferenceExpression();
			} else if (target is FieldReferenceExpression) {
				FieldReferenceExpression fRef = (FieldReferenceExpression)target;
				targetExpr = null;
				if (fRef.TargetObject is FieldReferenceExpression) {
					if (IsPossibleTypeReference((FieldReferenceExpression)fRef.TargetObject)) {
						targetExpr = ConvertToTypeReference((FieldReferenceExpression)fRef.TargetObject);
					}
				}
				if (targetExpr == null)
					targetExpr = (CodeExpression)fRef.TargetObject.AcceptVisitor(this, data);
				
				methodName = fRef.FieldName;
				// HACK for : Microsoft.VisualBasic.ChrW(NUMBER)
				if (methodName == "ChrW") {
					return new CodeCastExpression("System.Char", GetExpressionList(invocationExpression.Arguments)[0]);
				}
			} else if (target is IdentifierExpression) {
				targetExpr = new CodeThisReferenceExpression();
				methodName = ((IdentifierExpression)target).Identifier;
			} else {
				targetExpr = (CodeExpression)target.AcceptVisitor(this, data);
			}
			return new CodeMethodInvokeExpression(targetExpr, methodName, GetExpressionList(invocationExpression.Arguments));
		}
		
		public override object VisitIdentifierExpression(IdentifierExpression identifierExpression, object data)
		{
			if (!IsLocalVariable(identifierExpression.Identifier) && IsField(identifierExpression.Identifier)) {
				return new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), identifierExpression.Identifier);
			}
			return new CodeVariableReferenceExpression(identifierExpression.Identifier);
		}
		
		public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, object data)
		{
			CodeExpression var;
            CodeAssignStatement assign;

			switch (unaryOperatorExpression.Op) {
				case UnaryOperatorType.Minus:
					if (unaryOperatorExpression.Expression is PrimitiveExpression) {
						PrimitiveExpression expression = (PrimitiveExpression)unaryOperatorExpression.Expression;
						if (expression.Value is int) {
							return new CodePrimitiveExpression(- (int)expression.Value);
						}
						if (expression.Value is System.UInt32 || expression.Value is System.UInt16) {
							return new CodePrimitiveExpression(Int32.Parse("-" + expression.StringValue));
						}
						
						if (expression.Value is long) {
							return new CodePrimitiveExpression(- (long)expression.Value);
						}
						if (expression.Value is double) {
							return new CodePrimitiveExpression(- (double)expression.Value);
						}
						if (expression.Value is float) {
							return new CodePrimitiveExpression(- (float)expression.Value);
						}
						
					}
					return  new CodeBinaryOperatorExpression(new CodePrimitiveExpression(0),
					                                         CodeBinaryOperatorType.Subtract,
					                                         (CodeExpression)unaryOperatorExpression.Expression.AcceptVisitor(this, data));
				case UnaryOperatorType.Plus:
					return unaryOperatorExpression.Expression.AcceptVisitor(this, data);
					
				case UnaryOperatorType.PostIncrement:
					// emulate i++, with i = i + 1
					var = (CodeExpression)unaryOperatorExpression.Expression.AcceptVisitor(this, data);

                    assign = new CodeAssignStatement(var,
                                   new CodeBinaryOperatorExpression(var,
                                                                    CodeBinaryOperatorType.Add,
                                                                    new CodePrimitiveExpression(1)));

                    AddStmt(assign);

                    return assign;

                    //return new CodeAssignStatement(var,
                    //               new CodeBinaryOperatorExpression(var,
                    //                                                CodeBinaryOperatorType.Add,
                    //                                                new CodePrimitiveExpression(1)));

                    // RG: needs to return an Expression - Not a Statement
                    //return new CodeBinaryOperatorExpression(var,
                    //                               CodeBinaryOperatorType.Assign,
                    //                               new CodeBinaryOperatorExpression(var,
                    //                                                                CodeBinaryOperatorType.Add,
                    //                                                                new CodePrimitiveExpression(1)));
					
				case UnaryOperatorType.PostDecrement:
					// emulate i--, with i = i - 1
					var = (CodeExpression)unaryOperatorExpression.Expression.AcceptVisitor(this, data);

                    assign = new CodeAssignStatement(var,
                                                   new CodeBinaryOperatorExpression(var,
                                                                                    CodeBinaryOperatorType.Subtract,
                                                                                    new CodePrimitiveExpression(1)));

                    AddStmt(assign);

                    return assign;
	
                    //return new CodeAssignStatement(var,
                    //                               new CodeBinaryOperatorExpression(var,
                    //                                                                CodeBinaryOperatorType.Subtract,
                    //                                                                new CodePrimitiveExpression(1)));

                    // RG: needs to return an Expression - Not a Statement
                    //return new CodeBinaryOperatorExpression(var,
                    //               CodeBinaryOperatorType.Assign,
                    //               new CodeBinaryOperatorExpression(var,
                    //                                                CodeBinaryOperatorType.Subtract,
                    //                                                new CodePrimitiveExpression(1)));
	
				case UnaryOperatorType.Decrement:
					// emulate --i, with i = i - 1
					var = (CodeExpression)unaryOperatorExpression.Expression.AcceptVisitor(this, data);

                    assign = new CodeAssignStatement(var,
                                                   new CodeBinaryOperatorExpression(var,
                                                                                    CodeBinaryOperatorType.Subtract,
                                                                                    new CodePrimitiveExpression(1)));
                    AddStmt(assign);

                    return assign;
                    //return new CodeAssignStatement(var,
                    //                               new CodeBinaryOperatorExpression(var,
                    //                                                                CodeBinaryOperatorType.Subtract,
                    //                                                                new CodePrimitiveExpression(1)));

                    //return new CodeBinaryOperatorExpression(var,
                    //                CodeBinaryOperatorType.Assign,
                    //               new CodeBinaryOperatorExpression(var,
                    //                                                CodeBinaryOperatorType.Subtract,
                    //                                                new CodePrimitiveExpression(1)));
	
				case UnaryOperatorType.Increment:
					// emulate ++i, with i = i + 1
					var = (CodeExpression)unaryOperatorExpression.Expression.AcceptVisitor(this, data);

                    assign = new CodeAssignStatement(var,
                                                   new CodeBinaryOperatorExpression(var,
                                                                                    CodeBinaryOperatorType.Add,
                                                                                    new CodePrimitiveExpression(1)));

                    AddStmt(assign);

                    return assign;

                    //return new CodeAssignStatement(var,
                    //                               new CodeBinaryOperatorExpression(var,
                    //                                                                CodeBinaryOperatorType.Add,
                    //                                                                new CodePrimitiveExpression(1)));

                    //return new CodeBinaryOperatorExpression(var,
                    //                CodeBinaryOperatorType.Assign,
                    //                new CodeBinaryOperatorExpression(var,
                    //                                                CodeBinaryOperatorType.Add,
                    //                                                new CodePrimitiveExpression(1)));

                // RG: 
                case UnaryOperatorType.Not:
                    // emulate !a with a == false
                    var = (CodeExpression)unaryOperatorExpression.Expression.AcceptVisitor(this, data);

                    return new CodeBinaryOperatorExpression(var,CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(false));

                default:
                    throw new NotSupportedException("CodeDom does not support Unary Operators");
			}
		}

		bool methodReference = false;
		
		void AddEventHandler(Expression eventExpr, Expression handler, object data)
		{
			methodReference = true;
			CodeExpression methodInvoker = (CodeExpression)handler.AcceptVisitor(this, data);
			methodReference = false;
			if (!(methodInvoker is CodeObjectCreateExpression)) {
				// we need to create an event handler here
				methodInvoker = new CodeObjectCreateExpression(new CodeTypeReference("System.EventHandler"), methodInvoker);
			}
			
			if (eventExpr is IdentifierExpression) {
				AddStmt(new CodeAttachEventStatement(new CodeEventReferenceExpression(new CodeThisReferenceExpression(), ((IdentifierExpression)eventExpr).Identifier),
				                                     methodInvoker));
			} else {
				FieldReferenceExpression fr = (FieldReferenceExpression)eventExpr;
				AddStmt(new CodeAttachEventStatement(new CodeEventReferenceExpression((CodeExpression)fr.TargetObject.AcceptVisitor(this, data), fr.FieldName),
				                                     methodInvoker));
			}
		}
		
		public override object VisitAssignmentExpression(AssignmentExpression assignmentExpression, object data)
		{
			if (assignmentExpression.Op == AssignmentOperatorType.Add) {
				AddEventHandler(assignmentExpression.Left, assignmentExpression.Right, data);
			} else {
				if (assignmentExpression.Left is IdentifierExpression) {
					AddStmt(new CodeAssignStatement((CodeExpression)assignmentExpression.Left.AcceptVisitor(this, null), (CodeExpression)assignmentExpression.Right.AcceptVisitor(this, null)));
				} else {
					AddStmt(new CodeAssignStatement((CodeExpression)assignmentExpression.Left.AcceptVisitor(this, null), (CodeExpression)assignmentExpression.Right.AcceptVisitor(this, null)));
				}
			}
			return null;
		}
		
		public override object VisitAddHandlerStatement(AddHandlerStatement addHandlerStatement, object data)
		{
			AddEventHandler(addHandlerStatement.EventExpression, addHandlerStatement.HandlerExpression, data);
			return null;
		}
		
		public override object VisitAddressOfExpression(AddressOfExpression addressOfExpression, object data)
		{
			return addressOfExpression.Expression.AcceptVisitor(this, data);
		}

        public override object VisitUsing(Using @using, object data)
        {
            return base.VisitUsing(@using, data);
        }

        // RG
        int usingId = 0;

        public override object VisitUsingStatement(UsingStatement usingStatement, object data)
        {
            // using (new expr) { stmts; }
            //
            // emulate with 
            //      object _dispose; 
            //      try 
            //      { 
            //          _dispose = new expr;
            //
            //          stmts;
            //      } 
            //      finally 
            //      { 
            //          if (((_dispose != null)
            //              && (typeof(System.IDisposable).IsInstanceOfType(_dispose) == true)))
            //          {
            //              ((System.IDisposable)(_dispose)).Dispose();
            //          }
            //      }
            //

            usingId++; // in case nested using() statements
            string name = "_dispose" + usingId.ToString();

            CodeVariableDeclarationStatement disposable = new CodeVariableDeclarationStatement("System.Object", name, new CodePrimitiveExpression(null));

            AddStmt(disposable);

            CodeTryCatchFinallyStatement tryStmt = new CodeTryCatchFinallyStatement();

            CodeVariableReferenceExpression left1 = new CodeVariableReferenceExpression(name);

            codeStack.Push(NullStmtCollection); // send statements to nul Statement collection
            CodeExpression right1 = (CodeExpression)usingStatement.ResourceAcquisition.AcceptVisitor(this, data);
            codeStack.Pop();

            CodeAssignStatement assign1 = new CodeAssignStatement(left1, right1);

            tryStmt.TryStatements.Add(assign1);
            tryStmt.TryStatements.Add(new CodeSnippetStatement());

            codeStack.Push(tryStmt.TryStatements);
            usingStatement.EmbeddedStatement.AcceptChildren(this, data);
            codeStack.Pop();

            CodeMethodInvokeExpression isInstanceOfType = new CodeMethodInvokeExpression(new CodeTypeOfExpression(typeof(IDisposable)), "IsInstanceOfType", new CodeExpression[] { left1 });

            CodeConditionStatement if1 = new CodeConditionStatement();
            if1.Condition = new CodeBinaryOperatorExpression(new CodeBinaryOperatorExpression(left1, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression(null)),
                CodeBinaryOperatorType.BooleanAnd,
                    new CodeBinaryOperatorExpression(isInstanceOfType, CodeBinaryOperatorType.IdentityEquality, new CodePrimitiveExpression(true)));
            if1.TrueStatements.Add(new CodeMethodInvokeExpression(new CodeCastExpression(typeof(IDisposable),left1), "Dispose", new CodeExpression[] { }));

            tryStmt.FinallyStatements.Add(if1);

            // Add Statement to Current Statement Collection
            AddStmt(tryStmt);

            return null;
        }
		
		public override object VisitTypeOfExpression(TypeOfExpression typeOfExpression, object data)
		{
			return new CodeTypeOfExpression(ConvType(typeOfExpression.TypeReference));
		}

		public override object VisitCastExpression(CastExpression castExpression, object data)
		{
			CodeTypeReference typeRef = ConvType(castExpression.CastTo);
			return new CodeCastExpression(typeRef, (CodeExpression)castExpression.Expression.AcceptVisitor(this, data));
		}
		
		public override object VisitIndexerExpression(IndexerExpression indexerExpression, object data)
		{
			return new CodeIndexerExpression((CodeExpression)indexerExpression.TargetObject.AcceptVisitor(this, data), GetExpressionList(indexerExpression.Indexes));
		}
		
		public override object VisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression, object data)
		{
			return new CodeThisReferenceExpression();
		}
		
		public override object VisitBaseReferenceExpression(BaseReferenceExpression baseReferenceExpression, object data)
		{
			return new CodeBaseReferenceExpression();
		}
		
		public override object VisitArrayCreateExpression(ArrayCreateExpression arrayCreateExpression, object data)
		{
			if (arrayCreateExpression.ArrayInitializer == null) {
				return new CodeArrayCreateExpression(ConvType(arrayCreateExpression.CreateType),
				                                     arrayCreateExpression.Arguments[0].AcceptVisitor(this, data) as CodeExpression);
			}
			return new CodeArrayCreateExpression(ConvType(arrayCreateExpression.CreateType),
			                                     GetExpressionList(arrayCreateExpression.ArrayInitializer.CreateExpressions));
		}
		
		public override object VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression, object data)
		{
			return new CodeObjectCreateExpression(ConvType(objectCreateExpression.CreateType),
			                                      objectCreateExpression.Parameters == null ? null : GetExpressionList(objectCreateExpression.Parameters));
		}
		
		public override object VisitParameterDeclarationExpression(ParameterDeclarationExpression parameterDeclarationExpression, object data)
		{
			CodeParameterDeclarationExpression parameter = new CodeParameterDeclarationExpression(ConvType(parameterDeclarationExpression.TypeReference), parameterDeclarationExpression.ParameterName);

            parameters.Add(parameter);

            return parameter;
		}

        public override object VisitBreakStatement(BreakStatement breakStatement, object data)
        {
            // RG:
            // break;
            //
            // emulate with:
            //      goto break1;
            //
            Breakable breakable = breakableStack.Peek();

            breakable.IsBreak = true;

            CodeGotoStatement breakStmt = new CodeGotoStatement("break" + breakable.Id);

            AddStmt(breakStmt);

            return breakStmt;
        }

        public override object VisitContinueStatement(ContinueStatement continueStatement, object data)
        {
            // RG:
            // continue;
            //
            // emulate with:
            //      goto continue1;
            //
            Breakable breakable = breakableStack.Peek();

            // Is continuable?
            if (!breakable.AllowContinue)
            {
                // walk stack to find first continuable item
                Breakable[] stack = breakableStack.ToArray();
                foreach (Breakable b in stack)
                {
                    if (b.AllowContinue)
                    {
                        breakable = b;
                        break;
                    }
                }
            }

            breakable.IsContinue = true;

            CodeGotoStatement continueStmt = new CodeGotoStatement("continue" + breakable.Id);

            AddStmt(continueStmt);

            return continueStmt;
        }

		bool IsField(string type, string fieldName)
		{
			bool isField = environmentInformationProvider.HasField(type, fieldName);
			
			if (!isField) {
				int idx = type.LastIndexOf('.');
				if (idx >= 0) {
					type = type.Substring(0, idx) + "+" + type.Substring(idx + 1);
					isField = IsField(type, fieldName);
				}
			}
			
			return isField;
		}
		
		bool IsFieldReferenceExpression(FieldReferenceExpression fieldReferenceExpression)
		{
			if (fieldReferenceExpression.TargetObject is ThisReferenceExpression
			    || fieldReferenceExpression.TargetObject is BaseReferenceExpression)
			{
				//field detection for fields\props inherited from base classes
				return IsField(fieldReferenceExpression.FieldName);
			}
			return false;
		}
		
		public override object VisitFieldReferenceExpression(FieldReferenceExpression fieldReferenceExpression, object data)
		{
			if (methodReference) {
				methodReference = false;
				return new CodeMethodReferenceExpression((CodeExpression)fieldReferenceExpression.TargetObject.AcceptVisitor(this, data), fieldReferenceExpression.FieldName);
			}
			if (IsFieldReferenceExpression(fieldReferenceExpression)) {
				return new CodeFieldReferenceExpression((CodeExpression)fieldReferenceExpression.TargetObject.AcceptVisitor(this, data),
				                                        fieldReferenceExpression.FieldName);
			} else {
				if (fieldReferenceExpression.TargetObject is FieldReferenceExpression) {
					if (IsPossibleTypeReference((FieldReferenceExpression)fieldReferenceExpression.TargetObject)) {
						CodeTypeReferenceExpression typeRef = ConvertToTypeReference((FieldReferenceExpression)fieldReferenceExpression.TargetObject);
						if (IsField(typeRef.Type.BaseType, fieldReferenceExpression.FieldName)) {
							return new CodeFieldReferenceExpression(typeRef,
							                                        fieldReferenceExpression.FieldName);
						} else {
							return new CodePropertyReferenceExpression(typeRef,
							                                           fieldReferenceExpression.FieldName);
						}
					}
				}
				
				CodeExpression codeExpression = (CodeExpression)fieldReferenceExpression.TargetObject.AcceptVisitor(this, data);
				return new CodePropertyReferenceExpression(codeExpression,
				                                           fieldReferenceExpression.FieldName);
			}
		}

		#endregion
		
		#endregion
		bool IsPossibleTypeReference(FieldReferenceExpression fieldReferenceExpression)
		{
			while (fieldReferenceExpression.TargetObject is FieldReferenceExpression) {
				fieldReferenceExpression = (FieldReferenceExpression)fieldReferenceExpression.TargetObject;
			}
			IdentifierExpression identifier = fieldReferenceExpression.TargetObject as IdentifierExpression;
			if (identifier != null)
				return !IsField(identifier.Identifier) && !IsLocalVariable(identifier.Identifier);
			TypeReferenceExpression tre = fieldReferenceExpression.TargetObject as TypeReferenceExpression;
			if (tre != null)
				return true;
			return false;
		}
		
		bool IsLocalVariable(string identifier)
		{
			foreach (CodeVariableDeclarationStatement variable in variables) {
				if (variable.Name == identifier)
					return true;
			}

            foreach (CodeParameterDeclarationExpression parameter in parameters)
            {
                if (parameter.Name == identifier)
                    return true;
            }

			return false;
		}
		
		bool IsField(string identifier)
		{
			if (currentTypeDeclaration == null) // e.g. in unit tests
				return false;
			foreach (INode node in currentTypeDeclaration.Children) {
				if (node is FieldDeclaration) {
					FieldDeclaration fd = (FieldDeclaration)node;
					if (fd.GetVariableDeclaration(identifier) != null) {
						return true;
					}
				}
			}
			//field detection for fields\props inherited from base classes
			if (currentTypeDeclaration.BaseTypes.Count > 0) {
				return IsField(currentTypeDeclaration.BaseTypes[0].ToString(), identifier);
			}
			return false;
		}
		
		static CodeTypeReferenceExpression ConvertToTypeReference(FieldReferenceExpression fieldReferenceExpression)
		{
			StringBuilder type = new StringBuilder("");
			
			while (fieldReferenceExpression.TargetObject is FieldReferenceExpression) {
				type.Insert(0,'.');
				type.Insert(1,fieldReferenceExpression.FieldName.ToCharArray());
				fieldReferenceExpression = (FieldReferenceExpression)fieldReferenceExpression.TargetObject;
			}
			
			type.Insert(0,'.');
			type.Insert(1,fieldReferenceExpression.FieldName.ToCharArray());
			
			if (fieldReferenceExpression.TargetObject is IdentifierExpression) {
				type.Insert(0, ((IdentifierExpression)fieldReferenceExpression.TargetObject).Identifier.ToCharArray());
				string oldType = type.ToString();
				int idx = oldType.LastIndexOf('.');
				while (idx > 0) {
					if (Type.GetType(type.ToString()) != null) {
						break;
					}
					string stype = type.ToString().Substring(idx + 1);
					type = new StringBuilder(type.ToString().Substring(0, idx));
					type.Append("+");
					type.Append(stype);
					idx = type.ToString().LastIndexOf('.');
				}
				if (Type.GetType(type.ToString()) == null) {
					type = new StringBuilder(oldType);
				}
				return new CodeTypeReferenceExpression(type.ToString());
			} else if (fieldReferenceExpression.TargetObject is TypeReferenceExpression) {
				type.Insert(0, ((TypeReferenceExpression)fieldReferenceExpression.TargetObject).TypeReference.SystemType);
				return new CodeTypeReferenceExpression(type.ToString());
			} else {
				return null;
			}
		}
		
		CodeExpression[] GetExpressionList(IList expressionList)
		{
			if (expressionList == null) {
				return new CodeExpression[0];
			}
			CodeExpression[] list = new CodeExpression[expressionList.Count];
			for (int i = 0; i < expressionList.Count; ++i) {
				list[i] = (CodeExpression)((Expression)expressionList[i]).AcceptVisitor(this, null);
				if (list[i] == null) {
					list[i] = new CodePrimitiveExpression(0);
				}
			}
			return list;
		}
		
		
	}
}

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