context: using System;
  using System.Collections.Generic;
  using System.Text;
  using System.Reflection;
  using System.Reflection.Emit;
  using Emit = System.Reflection.Emit;
  
  namespace Server
  {
  	public class AssemblyEmitter
  	{
  		private string m_AssemblyName;
  
  		private AppDomain m_AppDomain;
  		private AssemblyBuilder m_AssemblyBuilder;
  		private ModuleBuilder m_ModuleBuilder;
  
  		public AssemblyEmitter( string assemblyName, bool canSave )
  		{
  			m_AssemblyName = assemblyName;
  
  			m_AppDomain = AppDomain.CurrentDomain;
  
  			m_AssemblyBuilder = m_AppDomain.DefineDynamicAssembly(
  				new AssemblyName( assemblyName ),
  				canSave ? AssemblyBuilderAccess.RunAndSave : AssemblyBuilderAccess.Run
  			);
  
  			if ( canSave )
  			{
  				m_ModuleBuilder = m_AssemblyBuilder.DefineDynamicModule(
  					assemblyName,
  					String.Format( "{0}.dll", assemblyName.ToLower() ),
  					false
  				);
  			}
  			else
  			{
  				m_ModuleBuilder = m_AssemblyBuilder.DefineDynamicModule(
  					assemblyName,
  					false
  				);
  			}
  		}
  
  		public TypeBuilder DefineType( string typeName, TypeAttributes attrs, Type parentType )
  		{
  			return m_ModuleBuilder.DefineType( typeName, attrs, parentType );
  		}
  
  		public void Save()
  		{
  			m_AssemblyBuilder.Save(
  				String.Format( "{0}.dll", m_AssemblyName.ToLower() )
  			);
  		}
  	}
  
  	public class MethodEmitter
  	{
  		private TypeBuilder m_TypeBuilder;
  
  		private MethodBuilder m_Builder;
  		private ILGenerator m_Generator;
  
  		private Type[] m_ArgumentTypes;
  
  		public TypeBuilder Type
  		{
  			get { return m_TypeBuilder; }
  		}
  
  		public ILGenerator Generator
  		{
  			get { return m_Generator; }
  		}
  
  		private class CallInfo
  		{
  			public Type type;
  			public MethodInfo method;
  
  			public int index;
  			public ParameterInfo[] parms;
  
  			public CallInfo( Type type, MethodInfo method )
  			{
  				this.type = type;
  				this.method = method;
  
  				this.parms = method.GetParameters();
  			}
  		}
  
  		private Stack<Type> m_Stack;
  		private Stack<CallInfo> m_Calls;
  
  		private Dictionary<Type, Queue<LocalBuilder>> m_Temps;
  
  		public MethodBuilder Method
  		{
  			get { return m_Builder; }
  		}
  
  		public MethodEmitter( TypeBuilder typeBuilder )
  		{
  			m_TypeBuilder = typeBuilder;
  
  			m_Temps = new Dictionary<Type, Queue<LocalBuilder>>();
  
  			m_Stack = new Stack<Type>();
  			m_Calls = new Stack<CallInfo>();
  		}
  
  		public void Define( string name, MethodAttributes attr, Type returnType, Type[] parms )
  		{
  			m_Builder = m_TypeBuilder.DefineMethod( name, attr, returnType, parms );
  			m_Generator = m_Builder.GetILGenerator();
  
  			m_ArgumentTypes = parms;
  		}
  
  		public LocalBuilder CreateLocal( Type localType )
  		{
  			return m_Generator.DeclareLocal( localType );
  		}
  
  		public LocalBuilder AcquireTemp( Type localType )
  		{
  			Queue<LocalBuilder> list;
  
  			if ( !m_Temps.TryGetValue( localType, out list ) )
  				m_Temps[localType] = list = new Queue<LocalBuilder>();
  
  			if ( list.Count > 0 )
  				return list.Dequeue();
  
  			return CreateLocal( localType );
  		}
  
  		public void ReleaseTemp( LocalBuilder local )
  		{
  			Queue<LocalBuilder> list;
  
  			if ( !m_Temps.TryGetValue( local.LocalType, out list ) )
  				m_Temps[local.LocalType] = list = new Queue<LocalBuilder>();
  
  			list.Enqueue( local );
  		}
  
  		public void Branch( Label label )
  		{
  			m_Generator.Emit( OpCodes.Br, label );
  		}
  
  		public void BranchIfFalse( Label label )
  		{
  			Pop( typeof( object ) );
  
  			m_Generator.Emit( OpCodes.Brfalse, label );
  		}
  
  		public void BranchIfTrue( Label label )
  		{
  			Pop( typeof( object ) );
  
  			m_Generator.Emit( OpCodes.Brtrue, label );
  		}
  
  		public Label CreateLabel()
  		{
  			return m_Generator.DefineLabel();
  		}
  
  		public void MarkLabel( Label label )
  		{
  			m_Generator.MarkLabel( label );
  		}
  
  		public void Pop()
  		{
  			m_Stack.Pop();
  		}
  
  		public void Pop( Type expected )
  		{
  			if ( expected == null )
  				throw new InvalidOperationException( "Expected type cannot be null." );
  
  			Type onStack = m_Stack.Pop();
  
  			if ( expected == typeof( bool ) )
  				expected = typeof( int );
  
  			if ( onStack == typeof( bool ) )
  				onStack = typeof( int );
  
  			if ( !expected.IsAssignableFrom( onStack ) )
  				throw new InvalidOperationException( "Unexpected stack state." );
  		}
  
  		public void Push( Type type )
  		{
  			m_Stack.Push( type );
  		}
  
  		public void Return()
  		{
  			if ( m_Stack.Count != ( m_Builder.ReturnType == typeof( void ) ? 0 : 1 ) )
  				throw new InvalidOperationException( "Stack return mismatch." );
  
  			m_Generator.Emit( OpCodes.Ret );
  		}
  
  		public void LoadNull()
  		{
  			LoadNull( typeof( object ) );
  		}
  
  		public void LoadNull( Type type )
  		{
  			Push( type );
  
  			m_Generator.Emit( OpCodes.Ldnull );
  		}
  
  		public void Load( string value )
  		{
  			Push( typeof( string ) );
  
  			if ( value != null )
  				m_Generator.Emit( OpCodes.Ldstr, value );
  			else
  				m_Generator.Emit( OpCodes.Ldnull );
  		}
  
  		public void Load( Enum value )
  		{
  			int toLoad = ((IConvertible)value).ToInt32( null );
  			Load( toLoad );
  
  			Pop();
  			Push( value.GetType() );
  		}
  
  		public void Load( long value )
  		{
  			Push( typeof( long ) );
  
  			m_Generator.Emit( OpCodes.Ldc_I8, value );
  		}
  
  		public void Load( float value )
  		{
  			Push( typeof( float ) );
  
  			m_Generator.Emit( OpCodes.Ldc_R4, value );
  		}
  
  		public void Load( double value )
  		{
  			Push( typeof( double ) );
  
  			m_Generator.Emit( OpCodes.Ldc_R8, value );
  		}
  
  		public void Load( char value )
  		{
  			Load( (int) value );
  
  			Pop();
  			Push( typeof( char ) );
  		}
  
  		public void Load( bool value )
  		{
  			Push( typeof( bool ) );
  
  			if ( value )
  				m_Generator.Emit( OpCodes.Ldc_I4_1 );
  			else
  				m_Generator.Emit( OpCodes.Ldc_I4_0 );
  		}
  
  		public void Load( int value )
  		{
  			Push( typeof( int ) );
  
  			switch ( value )
  			{
  				case -1:
  					m_Generator.Emit( OpCodes.Ldc_I4_M1 );
  					break;
  
  				case 0:
  					m_Generator.Emit( OpCodes.Ldc_I4_0 );
  					break;
  
  				case 1:
  					m_Generator.Emit( OpCodes.Ldc_I4_1 );
  					break;
  
  				case 2:
  					m_Generator.Emit( OpCodes.Ldc_I4_2 );
  					break;
  
  				case 3:
  					m_Generator.Emit( OpCodes.Ldc_I4_3 );
  					break;
  
  				case 4:
  					m_Generator.Emit( OpCodes.Ldc_I4_4 );
  					break;
  
  				case 5:
  					m_Generator.Emit( OpCodes.Ldc_I4_5 );
  					break;
  
  				case 6:
  
gt: 					m_Generator.Emit( OpCodes.Ldc_I4_6 );