context: // Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
  // 
  // Permission is hereby granted, free of charge, to any person obtaining a copy of this
  // software and associated documentation files (the "Software"), to deal in the Software
  // without restriction, including without limitation the rights to use, copy, modify, merge,
  // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
  // to whom the Software is furnished to do so, subject to the following conditions:
  // 
  // The above copyright notice and this permission notice shall be included in all copies or
  // substantial portions of the Software.
  // 
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
  // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  // DEALINGS IN THE SOFTWARE.
  
  using System;
  using System.Collections.Generic;
  using System.Diagnostics;
  using System.IO;
  using System.Linq;
  using System.Text;
  using ICSharpCode.Decompiler;
  using ICSharpCode.Decompiler.Disassembler;
  using ICSharpCode.NRefactory.Utils;
  using Mono.Cecil;
  using Mono.Cecil.Cil;
  using Mono.CSharp;
  using Cecil = Mono.Cecil;
  
  namespace ICSharpCode.Decompiler.ILAst
  {
  	public abstract class ILNode
  	{
  		public IEnumerable<T> GetSelfAndChildrenRecursive<T>(Func<T, bool> predicate = null) where T: ILNode
  		{
  			List<T> result = new List<T>(16);
  			AccumulateSelfAndChildrenRecursive(result, predicate);
  			return result;
  		}
  		
  		void AccumulateSelfAndChildrenRecursive<T>(List<T> list, Func<T, bool> predicate) where T:ILNode
  		{
  			T thisAsT = this as T;
  			if (thisAsT != null && (predicate == null || predicate(thisAsT)))
  				list.Add(thisAsT);
  			foreach (ILNode node in this.GetChildren()) {
  				if (node != null)
  					node.AccumulateSelfAndChildrenRecursive(list, predicate);
  			}
  		}
  		
  		public virtual IEnumerable<ILNode> GetChildren()
  		{
  			yield break;
  		}
  		
  		public override string ToString()
  		{
  			StringWriter w = new StringWriter();
  			WriteTo(new PlainTextOutput(w));
  			return w.ToString().Replace("\r\n", "; ");
  		}
  		
  		public abstract void WriteTo(ITextOutput output);
  	}
  	
  	public class ILBlock: ILNode
  	{
  		public ILExpression EntryGoto;
  		
  		public List<ILNode> Body;
  		
  		public ILBlock(params ILNode[] body)
  		{
  			this.Body = new List<ILNode>(body);
  		}
  		
  		public ILBlock(List<ILNode> body)
  		{
  			this.Body = body;
  		}
  		
  		public override IEnumerable<ILNode> GetChildren()
  		{
  			if (this.EntryGoto != null)
  				yield return this.EntryGoto;
  			foreach(ILNode child in this.Body) {
  				yield return child;
  			}
  		}
  		
  		public override void WriteTo(ITextOutput output)
  		{
  			foreach(ILNode child in this.GetChildren()) {
  				child.WriteTo(output);
  				output.WriteLine();
  			}
  		}
  	}
  	
  	public class ILBasicBlock: ILNode
  	{
  		/// <remarks> Body has to start with a label and end with unconditional control flow </remarks>
  		public List<ILNode> Body = new List<ILNode>();
  		
  		public override IEnumerable<ILNode> GetChildren()
  		{
  			return this.Body;
  		}
  		
  		public override void WriteTo(ITextOutput output)
  		{
  			foreach(ILNode child in this.GetChildren()) {
  				child.WriteTo(output);
  				output.WriteLine();
  			}
  		}
  	}
  	
  	public class ILLabel: ILNode
  	{
  		public string Name;
  
  		public override void WriteTo(ITextOutput output)
  		{
  			output.WriteDefinition(Name + ":", this);
  		}
  	}
  	
  	public class ILTryCatchBlock: ILNode
  	{
  		public class CatchBlock: ILBlock
  		{
  			public TypeReference ExceptionType;
  			public ILVariable ExceptionVariable;
  			
  			public override void WriteTo(ITextOutput output)
  			{
  				output.Write("catch ");
  				output.WriteReference(ExceptionType.FullName, ExceptionType);
  				output.WriteLine(" {");
  				output.Indent();
  				base.WriteTo(output);
  				output.Unindent();
  				output.WriteLine("}");
  			}
  		}
  		
  		public ILBlock          TryBlock;
  		public List<CatchBlock> CatchBlocks;
  		public ILBlock          FinallyBlock;
  		public ILBlock          FaultBlock;
  		
  		public override IEnumerable<ILNode> GetChildren()
  		{
  			if (this.TryBlock != null)
  				yield return this.TryBlock;
  			foreach (var catchBlock in this.CatchBlocks) {
  				yield return catchBlock;
  			}
  			if (this.FaultBlock != null)
  				yield return this.FaultBlock;
  			if (this.FinallyBlock != null)
  				yield return this.FinallyBlock;
  		}
  		
  		public override void WriteTo(ITextOutput output)
  		{
  			output.WriteLine(".try {");
  			output.Indent();
  			TryBlock.WriteTo(output);
  			output.Unindent();
  			output.WriteLine("}");
  			foreach (CatchBlock block in CatchBlocks) {
  				block.WriteTo(output);
  			}
  			if (FaultBlock != null) {
  				output.WriteLine("fault {");
  				output.Indent();
  				FaultBlock.WriteTo(output);
  				output.Unindent();
  				output.WriteLine("}");
  			}
  			if (FinallyBlock != null) {
  				output.WriteLine("finally {");
  				output.Indent();
  				FinallyBlock.WriteTo(output);
  				output.Unindent();
  				output.WriteLine("}");
  			}
  		}
  	}
  	
  	public class ILVariable
  	{
  		public string Name;
  		public bool   IsGenerated;
  		public TypeReference Type;
  		public VariableDefinition OriginalVariable;
  		public ParameterDefinition OriginalParameter;
  		
  		public bool IsPinned {
  			get { return OriginalVariable != null && OriginalVariable.IsPinned; }
  		}
  		
  		public bool IsParameter {
  			get { return OriginalParameter != null; }
  		}
  		
  		public override string ToString()
  		{
  			return Name;
  		}
  	}
  	
  	public class ILRange
  	{
  		public int From;
  		public int To;   // Exlusive
  		
  		public override string ToString()
  		{
  			return string.Format("{0}-{1}", From.ToString("X"), To.ToString("X"));
  		}
  		
  		public static List<ILRange> OrderAndJoint(IEnumerable<ILRange> input)
  		{
  			if (input == null)
  				throw new ArgumentNullException("Input is null!");
  			
  			List<ILRange> ranges = input.Where(r => r != null).OrderBy(r => r.From).ToList();
  			for (int i = 0; i < ranges.Count - 1;) {
  				ILRange curr = ranges[i];
  				ILRange next = ranges[i + 1];
  				// Merge consequtive ranges if they intersect
  				if (curr.From <= next.From && next.From <= curr.To) {
  					curr.To = Math.Max(curr.To, next.To);
  					ranges.RemoveAt(i + 1);
  				} else {
  					i++;
  				}
  			}
  			return ranges;
  		}
  		
  		public static IEnumerable<ILRange> Invert(IEnumerable<ILRange> input, int codeSize)
  		{
  			if (input == null)
  				throw new ArgumentNullException("Input is null!");
  			
  			if (codeSize <= 0)
  				throw new ArgumentException("Code size must be grater than 0");
  			
  			var ordered = OrderAndJoint(input);
  			if (ordered.Count == 0) {
  				yield return new ILRange() { From = 0, To = codeSize };
  			} else {
  				// Gap before the first element
  
gt: 				if (ordered.First().From != 0)