mirror of https://github.com/icsharpcode/ILSpy.git
				
				
			
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							1250 lines
						
					
					
						
							51 KiB
						
					
					
				
			
		
		
	
	
							1250 lines
						
					
					
						
							51 KiB
						
					
					
				// 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.Concurrent; | 
						|
using System.Collections.Generic; | 
						|
using System.Diagnostics; | 
						|
using System.Linq; | 
						|
using System.Threading; | 
						|
 | 
						|
using ICSharpCode.Decompiler.Ast.Transforms; | 
						|
using ICSharpCode.Decompiler.ILAst; | 
						|
using ICSharpCode.NRefactory.CSharp; | 
						|
using ICSharpCode.NRefactory.PatternMatching; | 
						|
using ICSharpCode.NRefactory.Utils; | 
						|
using Mono.Cecil; | 
						|
using Mono.Cecil.Cil; | 
						|
 | 
						|
namespace ICSharpCode.Decompiler.Ast | 
						|
{ | 
						|
	using Ast = ICSharpCode.NRefactory.CSharp; | 
						|
	using Cecil = Mono.Cecil; | 
						|
	 | 
						|
	public class AstMethodBodyBuilder | 
						|
	{ | 
						|
		MethodDefinition methodDef; | 
						|
		TypeSystem typeSystem; | 
						|
		DecompilerContext context; | 
						|
		HashSet<ILVariable> localVariablesToDefine = new HashSet<ILVariable>(); // local variables that are missing a definition | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Creates the body for the method definition. | 
						|
		/// </summary> | 
						|
		/// <param name="methodDef">Method definition to decompile.</param> | 
						|
		/// <param name="context">Decompilation context.</param> | 
						|
		/// <param name="parameters">Parameter declarations of the method being decompiled. | 
						|
		/// These are used to update the parameter names when the decompiler generates names for the parameters.</param> | 
						|
		/// <returns>Block for the method body</returns> | 
						|
		public static BlockStatement CreateMethodBody(MethodDefinition methodDef, | 
						|
		                                              DecompilerContext context, | 
						|
		                                              IEnumerable<ParameterDeclaration> parameters = null) | 
						|
		{ | 
						|
			MethodDefinition oldCurrentMethod = context.CurrentMethod; | 
						|
			Debug.Assert(oldCurrentMethod == null || oldCurrentMethod == methodDef); | 
						|
			context.CurrentMethod = methodDef; | 
						|
			context.CurrentMethodIsAsync = false; | 
						|
			try { | 
						|
				AstMethodBodyBuilder builder = new AstMethodBodyBuilder(); | 
						|
				builder.methodDef = methodDef; | 
						|
				builder.context = context; | 
						|
				builder.typeSystem = methodDef.Module.TypeSystem; | 
						|
				if (Debugger.IsAttached) { | 
						|
					return builder.CreateMethodBody(parameters); | 
						|
				} else { | 
						|
					try { | 
						|
						return builder.CreateMethodBody(parameters); | 
						|
					} catch (OperationCanceledException) { | 
						|
						throw; | 
						|
					} catch (Exception ex) { | 
						|
						throw new ICSharpCode.Decompiler.DecompilerException(methodDef, ex); | 
						|
					} | 
						|
				} | 
						|
			} finally { | 
						|
				context.CurrentMethod = oldCurrentMethod; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		public BlockStatement CreateMethodBody(IEnumerable<ParameterDeclaration> parameters) | 
						|
		{ | 
						|
			if (methodDef.Body == null) { | 
						|
				return null; | 
						|
			} | 
						|
			 | 
						|
			context.CancellationToken.ThrowIfCancellationRequested(); | 
						|
			ILBlock ilMethod = new ILBlock(); | 
						|
			ILAstBuilder astBuilder = new ILAstBuilder(); | 
						|
			ilMethod.Body = astBuilder.Build(methodDef, true, context); | 
						|
			 | 
						|
			context.CancellationToken.ThrowIfCancellationRequested(); | 
						|
			ILAstOptimizer bodyGraph = new ILAstOptimizer(); | 
						|
			bodyGraph.Optimize(context, ilMethod); | 
						|
			context.CancellationToken.ThrowIfCancellationRequested(); | 
						|
			 | 
						|
			var localVariables = ilMethod.GetSelfAndChildrenRecursive<ILExpression>().Select(e => e.Operand as ILVariable) | 
						|
				.Where(v => v != null && !v.IsParameter).Distinct(); | 
						|
			Debug.Assert(context.CurrentMethod == methodDef); | 
						|
			NameVariables.AssignNamesToVariables(context, astBuilder.Parameters, localVariables, ilMethod); | 
						|
			 | 
						|
			if (parameters != null) { | 
						|
				foreach (var pair in (from p in parameters | 
						|
				                      join v in astBuilder.Parameters on p.Annotation<ParameterDefinition>() equals v.OriginalParameter | 
						|
				                      select new { p, v.Name })) | 
						|
				{ | 
						|
					pair.p.Name = pair.Name; | 
						|
				} | 
						|
			} | 
						|
			 | 
						|
			context.CancellationToken.ThrowIfCancellationRequested(); | 
						|
			Ast.BlockStatement astBlock = TransformBlock(ilMethod); | 
						|
			CommentStatement.ReplaceAll(astBlock); // convert CommentStatements to Comments | 
						|
			 | 
						|
			Statement insertionPoint = astBlock.Statements.FirstOrDefault(); | 
						|
			foreach (ILVariable v in localVariablesToDefine) { | 
						|
				AstType type; | 
						|
				if (v.Type.ContainsAnonymousType()) | 
						|
					type = new SimpleType("var"); | 
						|
				else | 
						|
					type = AstBuilder.ConvertType(v.Type); | 
						|
				var newVarDecl = new VariableDeclarationStatement(type, v.Name); | 
						|
				newVarDecl.Variables.Single().AddAnnotation(v); | 
						|
				astBlock.Statements.InsertBefore(insertionPoint, newVarDecl); | 
						|
			} | 
						|
			 | 
						|
			astBlock.AddAnnotation(new MemberMapping(methodDef) { LocalVariables = localVariables }); | 
						|
			 | 
						|
			return astBlock; | 
						|
		} | 
						|
		 | 
						|
		Ast.BlockStatement TransformBlock(ILBlock block) | 
						|
		{ | 
						|
			Ast.BlockStatement astBlock = new BlockStatement(); | 
						|
			if (block != null) { | 
						|
				foreach(ILNode node in block.GetChildren()) { | 
						|
					astBlock.Statements.AddRange(TransformNode(node)); | 
						|
				} | 
						|
			} | 
						|
			return astBlock; | 
						|
		} | 
						|
		 | 
						|
		IEnumerable<Statement> TransformNode(ILNode node) | 
						|
		{ | 
						|
			if (node is ILLabel) { | 
						|
				yield return new Ast.LabelStatement { Label = ((ILLabel)node).Name }; | 
						|
			} else if (node is ILExpression) { | 
						|
				List<ILRange> ilRanges = ILRange.OrderAndJoint(node.GetSelfAndChildrenRecursive<ILExpression>().SelectMany(e => e.ILRanges)); | 
						|
				AstNode codeExpr = TransformExpression((ILExpression)node); | 
						|
				if (codeExpr != null) { | 
						|
					codeExpr = codeExpr.WithAnnotation(ilRanges); | 
						|
					if (codeExpr is Ast.Expression) { | 
						|
						yield return new Ast.ExpressionStatement { Expression = (Ast.Expression)codeExpr }; | 
						|
					} else if (codeExpr is Ast.Statement) { | 
						|
						yield return (Ast.Statement)codeExpr; | 
						|
					} else { | 
						|
						throw new Exception(); | 
						|
					} | 
						|
				} | 
						|
			} else if (node is ILWhileLoop) { | 
						|
				ILWhileLoop ilLoop = (ILWhileLoop)node; | 
						|
				WhileStatement whileStmt = new WhileStatement() { | 
						|
					Condition = ilLoop.Condition != null ? (Expression)TransformExpression(ilLoop.Condition) : new PrimitiveExpression(true), | 
						|
					EmbeddedStatement = TransformBlock(ilLoop.BodyBlock) | 
						|
				}; | 
						|
				yield return whileStmt; | 
						|
			} else if (node is ILCondition) { | 
						|
				ILCondition conditionalNode = (ILCondition)node; | 
						|
				bool hasFalseBlock = conditionalNode.FalseBlock.EntryGoto != null || conditionalNode.FalseBlock.Body.Count > 0; | 
						|
				yield return new Ast.IfElseStatement { | 
						|
					Condition = (Expression)TransformExpression(conditionalNode.Condition), | 
						|
					TrueStatement = TransformBlock(conditionalNode.TrueBlock), | 
						|
					FalseStatement = hasFalseBlock ? TransformBlock(conditionalNode.FalseBlock) : null | 
						|
				}; | 
						|
			} else if (node is ILSwitch) { | 
						|
				ILSwitch ilSwitch = (ILSwitch)node; | 
						|
				if (TypeAnalysis.IsBoolean(ilSwitch.Condition.InferredType) && ( | 
						|
					from cb in ilSwitch.CaseBlocks | 
						|
					where cb.Values != null | 
						|
					from val in cb.Values | 
						|
					select val | 
						|
				).Any(val => val != 0 && val != 1)) | 
						|
				{ | 
						|
					// If switch cases contain values other then 0 and 1, force the condition to be non-boolean | 
						|
					ilSwitch.Condition.ExpectedType = typeSystem.Int32; | 
						|
				} | 
						|
				SwitchStatement switchStmt = new SwitchStatement() { Expression = (Expression)TransformExpression(ilSwitch.Condition) }; | 
						|
				foreach (var caseBlock in ilSwitch.CaseBlocks) { | 
						|
					SwitchSection section = new SwitchSection(); | 
						|
					if (caseBlock.Values != null) { | 
						|
						section.CaseLabels.AddRange(caseBlock.Values.Select(i => new CaseLabel() { Expression = AstBuilder.MakePrimitive(i, ilSwitch.Condition.ExpectedType ?? ilSwitch.Condition.InferredType) })); | 
						|
					} else { | 
						|
						section.CaseLabels.Add(new CaseLabel()); | 
						|
					} | 
						|
					section.Statements.Add(TransformBlock(caseBlock)); | 
						|
					switchStmt.SwitchSections.Add(section); | 
						|
				} | 
						|
				yield return switchStmt; | 
						|
			} else if (node is ILTryCatchBlock) { | 
						|
				ILTryCatchBlock tryCatchNode = ((ILTryCatchBlock)node); | 
						|
				var tryCatchStmt = new Ast.TryCatchStatement(); | 
						|
				tryCatchStmt.TryBlock = TransformBlock(tryCatchNode.TryBlock); | 
						|
				foreach (var catchClause in tryCatchNode.CatchBlocks) { | 
						|
					if (catchClause.ExceptionVariable == null | 
						|
					    && (catchClause.ExceptionType == null || catchClause.ExceptionType.MetadataType == MetadataType.Object)) | 
						|
					{ | 
						|
						tryCatchStmt.CatchClauses.Add(new Ast.CatchClause { Body = TransformBlock(catchClause) }); | 
						|
					} else { | 
						|
						tryCatchStmt.CatchClauses.Add( | 
						|
							new Ast.CatchClause { | 
						|
								Type = AstBuilder.ConvertType(catchClause.ExceptionType), | 
						|
								VariableName = catchClause.ExceptionVariable == null ? null : catchClause.ExceptionVariable.Name, | 
						|
								Body = TransformBlock(catchClause) | 
						|
							}.WithAnnotation(catchClause.ExceptionVariable)); | 
						|
					} | 
						|
				} | 
						|
				if (tryCatchNode.FinallyBlock != null) | 
						|
					tryCatchStmt.FinallyBlock = TransformBlock(tryCatchNode.FinallyBlock); | 
						|
				if (tryCatchNode.FaultBlock != null) { | 
						|
					CatchClause cc = new CatchClause(); | 
						|
					cc.Body = TransformBlock(tryCatchNode.FaultBlock); | 
						|
					cc.Body.Add(new ThrowStatement()); // rethrow | 
						|
					tryCatchStmt.CatchClauses.Add(cc); | 
						|
				} | 
						|
				yield return tryCatchStmt; | 
						|
			} else if (node is ILFixedStatement) { | 
						|
				ILFixedStatement fixedNode = (ILFixedStatement)node; | 
						|
				FixedStatement fixedStatement = new FixedStatement(); | 
						|
				foreach (ILExpression initializer in fixedNode.Initializers) { | 
						|
					Debug.Assert(initializer.Code == ILCode.Stloc); | 
						|
					ILVariable v = (ILVariable)initializer.Operand; | 
						|
					fixedStatement.Variables.Add( | 
						|
						new VariableInitializer { | 
						|
							Name = v.Name, | 
						|
							Initializer = (Expression)TransformExpression(initializer.Arguments[0]) | 
						|
						}.WithAnnotation(v)); | 
						|
				} | 
						|
				fixedStatement.Type = AstBuilder.ConvertType(((ILVariable)fixedNode.Initializers[0].Operand).Type); | 
						|
				fixedStatement.EmbeddedStatement = TransformBlock(fixedNode.BodyBlock); | 
						|
				yield return fixedStatement; | 
						|
			} else if (node is ILBlock) { | 
						|
				yield return TransformBlock((ILBlock)node); | 
						|
			} else { | 
						|
				throw new Exception("Unknown node type"); | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		AstNode TransformExpression(ILExpression expr) | 
						|
		{ | 
						|
			AstNode node = TransformByteCode(expr); | 
						|
			Expression astExpr = node as Expression; | 
						|
			 | 
						|
			// get IL ranges - used in debugger | 
						|
			List<ILRange> ilRanges = ILRange.OrderAndJoint(expr.GetSelfAndChildrenRecursive<ILExpression>().SelectMany(e => e.ILRanges)); | 
						|
			AstNode result; | 
						|
			 | 
						|
			if (astExpr != null) | 
						|
				result = Convert(astExpr, expr.InferredType, expr.ExpectedType); | 
						|
			else | 
						|
				result = node; | 
						|
			 | 
						|
			if (result != null) | 
						|
				result = result.WithAnnotation(new TypeInformation(expr.InferredType)); | 
						|
			 | 
						|
			if (result != null) | 
						|
				return result.WithAnnotation(ilRanges); | 
						|
			 | 
						|
			return result; | 
						|
		} | 
						|
		 | 
						|
		AstNode TransformByteCode(ILExpression byteCode) | 
						|
		{ | 
						|
			object operand = byteCode.Operand; | 
						|
			AstType operandAsTypeRef = AstBuilder.ConvertType(operand as Cecil.TypeReference); | 
						|
 | 
						|
			List<Ast.Expression> args = new List<Expression>(); | 
						|
			foreach(ILExpression arg in byteCode.Arguments) { | 
						|
				args.Add((Ast.Expression)TransformExpression(arg)); | 
						|
			} | 
						|
			Ast.Expression arg1 = args.Count >= 1 ? args[0] : null; | 
						|
			Ast.Expression arg2 = args.Count >= 2 ? args[1] : null; | 
						|
			Ast.Expression arg3 = args.Count >= 3 ? args[2] : null; | 
						|
			 | 
						|
			switch (byteCode.Code) { | 
						|
					#region Arithmetic | 
						|
				case ILCode.Add: | 
						|
				case ILCode.Add_Ovf: | 
						|
				case ILCode.Add_Ovf_Un: | 
						|
					{ | 
						|
						BinaryOperatorExpression boe; | 
						|
						if (byteCode.InferredType is PointerType) { | 
						|
							if (byteCode.Arguments[0].ExpectedType is PointerType) { | 
						|
								arg2 = DivideBySize(arg2, ((PointerType)byteCode.InferredType).ElementType); | 
						|
								boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); | 
						|
								boe.AddAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation); | 
						|
							} else if (byteCode.Arguments[1].ExpectedType is PointerType) { | 
						|
								arg1 = DivideBySize(arg1, ((PointerType)byteCode.InferredType).ElementType); | 
						|
								boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); | 
						|
								boe.AddAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation); | 
						|
							} else { | 
						|
								boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); | 
						|
							} | 
						|
						} else { | 
						|
							boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); | 
						|
						} | 
						|
						boe.AddAnnotation(byteCode.Code == ILCode.Add ? AddCheckedBlocks.UncheckedAnnotation : AddCheckedBlocks.CheckedAnnotation); | 
						|
						return boe; | 
						|
					} | 
						|
				case ILCode.Sub: | 
						|
				case ILCode.Sub_Ovf: | 
						|
				case ILCode.Sub_Ovf_Un: | 
						|
					{ | 
						|
						BinaryOperatorExpression boe; | 
						|
						if (byteCode.InferredType is PointerType) { | 
						|
							if (byteCode.Arguments[0].ExpectedType is PointerType) { | 
						|
								arg2 = DivideBySize(arg2, ((PointerType)byteCode.InferredType).ElementType); | 
						|
								boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2); | 
						|
								boe.WithAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation); | 
						|
							} else { | 
						|
								boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2); | 
						|
							} | 
						|
						} else { | 
						|
							boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2); | 
						|
						} | 
						|
						boe.AddAnnotation(byteCode.Code == ILCode.Sub ? AddCheckedBlocks.UncheckedAnnotation : AddCheckedBlocks.CheckedAnnotation); | 
						|
						return boe; | 
						|
					} | 
						|
					case ILCode.Div:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2); | 
						|
					case ILCode.Div_Un:     return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2); | 
						|
					case ILCode.Mul:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2).WithAnnotation(AddCheckedBlocks.UncheckedAnnotation); | 
						|
					case ILCode.Mul_Ovf:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2).WithAnnotation(AddCheckedBlocks.CheckedAnnotation); | 
						|
					case ILCode.Mul_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2).WithAnnotation(AddCheckedBlocks.CheckedAnnotation); | 
						|
					case ILCode.Rem:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2); | 
						|
					case ILCode.Rem_Un:     return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2); | 
						|
					case ILCode.And:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.BitwiseAnd, arg2); | 
						|
					case ILCode.Or:         return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.BitwiseOr, arg2); | 
						|
					case ILCode.Xor:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ExclusiveOr, arg2); | 
						|
					case ILCode.Shl:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftLeft, arg2); | 
						|
					case ILCode.Shr:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2); | 
						|
					case ILCode.Shr_Un:     return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2); | 
						|
					case ILCode.Neg:        return new Ast.UnaryOperatorExpression(UnaryOperatorType.Minus, arg1).WithAnnotation(AddCheckedBlocks.UncheckedAnnotation); | 
						|
					case ILCode.Not:        return new Ast.UnaryOperatorExpression(UnaryOperatorType.BitNot, arg1); | 
						|
				case ILCode.PostIncrement: | 
						|
				case ILCode.PostIncrement_Ovf: | 
						|
				case ILCode.PostIncrement_Ovf_Un: | 
						|
					{ | 
						|
						if (arg1 is DirectionExpression) | 
						|
							arg1 = ((DirectionExpression)arg1).Expression.Detach(); | 
						|
						var uoe = new Ast.UnaryOperatorExpression( | 
						|
							(int)byteCode.Operand > 0 ? UnaryOperatorType.PostIncrement : UnaryOperatorType.PostDecrement, arg1); | 
						|
						uoe.AddAnnotation((byteCode.Code == ILCode.PostIncrement) ? AddCheckedBlocks.UncheckedAnnotation : AddCheckedBlocks.CheckedAnnotation); | 
						|
						return uoe; | 
						|
					} | 
						|
					#endregion | 
						|
					#region Arrays | 
						|
					case ILCode.Newarr: { | 
						|
						var ace = new Ast.ArrayCreateExpression(); | 
						|
						ace.Type = operandAsTypeRef; | 
						|
						ComposedType ct = operandAsTypeRef as ComposedType; | 
						|
						if (ct != null) { | 
						|
							// change "new (int[,])[10] to new int[10][,]" | 
						|
							ct.ArraySpecifiers.MoveTo(ace.AdditionalArraySpecifiers); | 
						|
						} | 
						|
						if (byteCode.Code == ILCode.InitArray) { | 
						|
							ace.Initializer = new ArrayInitializerExpression(); | 
						|
							ace.Initializer.Elements.AddRange(args); | 
						|
						} else { | 
						|
							ace.Arguments.Add(arg1); | 
						|
						} | 
						|
						return ace; | 
						|
					} | 
						|
					case ILCode.InitArray: { | 
						|
						var ace = new Ast.ArrayCreateExpression(); | 
						|
						ace.Type = operandAsTypeRef; | 
						|
						ComposedType ct = operandAsTypeRef as ComposedType; | 
						|
						var arrayType = (ArrayType) operand; | 
						|
						if (ct != null) | 
						|
						{ | 
						|
							// change "new (int[,])[10] to new int[10][,]" | 
						|
							ct.ArraySpecifiers.MoveTo(ace.AdditionalArraySpecifiers); | 
						|
							ace.Initializer = new ArrayInitializerExpression(); | 
						|
						} | 
						|
						var newArgs = new List<Expression>(); | 
						|
						foreach (var arrayDimension in arrayType.Dimensions.Skip(1).Reverse()) | 
						|
						{ | 
						|
							int length = (int)arrayDimension.UpperBound - (int)arrayDimension.LowerBound; | 
						|
							for (int j = 0; j < args.Count; j += length) | 
						|
							{ | 
						|
								var child = new ArrayInitializerExpression(); | 
						|
								child.Elements.AddRange(args.GetRange(j, length)); | 
						|
								newArgs.Add(child); | 
						|
							} | 
						|
							var temp = args; | 
						|
							args = newArgs; | 
						|
							newArgs = temp; | 
						|
							newArgs.Clear(); | 
						|
						} | 
						|
						ace.Initializer.Elements.AddRange(args); | 
						|
						return ace; | 
						|
					} | 
						|
					case ILCode.Ldlen: return arg1.Member("Length"); | 
						|
				case ILCode.Ldelem_I: | 
						|
				case ILCode.Ldelem_I1: | 
						|
				case ILCode.Ldelem_I2: | 
						|
				case ILCode.Ldelem_I4: | 
						|
				case ILCode.Ldelem_I8: | 
						|
				case ILCode.Ldelem_U1: | 
						|
				case ILCode.Ldelem_U2: | 
						|
				case ILCode.Ldelem_U4: | 
						|
				case ILCode.Ldelem_R4: | 
						|
				case ILCode.Ldelem_R8: | 
						|
				case ILCode.Ldelem_Ref: | 
						|
				case ILCode.Ldelem_Any: | 
						|
					return arg1.Indexer(arg2); | 
						|
				case ILCode.Ldelema: | 
						|
					return MakeRef(arg1.Indexer(arg2)); | 
						|
				case ILCode.Stelem_I: | 
						|
				case ILCode.Stelem_I1: | 
						|
				case ILCode.Stelem_I2: | 
						|
				case ILCode.Stelem_I4: | 
						|
				case ILCode.Stelem_I8: | 
						|
				case ILCode.Stelem_R4: | 
						|
				case ILCode.Stelem_R8: | 
						|
				case ILCode.Stelem_Ref: | 
						|
				case ILCode.Stelem_Any: | 
						|
					return new Ast.AssignmentExpression(arg1.Indexer(arg2), arg3); | 
						|
				case ILCode.CompoundAssignment: | 
						|
					{ | 
						|
						CastExpression cast = arg1 as CastExpression; | 
						|
						var boe = cast != null ? (BinaryOperatorExpression)cast.Expression : arg1 as BinaryOperatorExpression; | 
						|
						// AssignmentExpression doesn't support overloaded operators so they have to be processed to BinaryOperatorExpression | 
						|
						if (boe == null) { | 
						|
							var tmp = new ParenthesizedExpression(arg1); | 
						|
							ReplaceMethodCallsWithOperators.ProcessInvocationExpression((InvocationExpression)arg1); | 
						|
							boe = (BinaryOperatorExpression)tmp.Expression; | 
						|
						} | 
						|
						var assignment = new Ast.AssignmentExpression { | 
						|
							Left = boe.Left.Detach(), | 
						|
							Operator = ReplaceMethodCallsWithOperators.GetAssignmentOperatorForBinaryOperator(boe.Operator), | 
						|
							Right = boe.Right.Detach() | 
						|
						}.CopyAnnotationsFrom(boe); | 
						|
						// We do not mark the resulting assignment as RestoreOriginalAssignOperatorAnnotation, because | 
						|
						// the operator cannot be translated back to the expanded form (as the left-hand expression | 
						|
						// would be evaluated twice, and might have side-effects) | 
						|
						if (cast != null) { | 
						|
							cast.Expression = assignment; | 
						|
							return cast; | 
						|
						} else { | 
						|
							return assignment; | 
						|
						} | 
						|
					} | 
						|
					#endregion | 
						|
					#region Comparison | 
						|
					case ILCode.Ceq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2); | 
						|
					case ILCode.Cne: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2); | 
						|
					case ILCode.Cgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); | 
						|
					case ILCode.Cgt_Un: { | 
						|
						// can also mean Inequality, when used with object references | 
						|
						TypeReference arg1Type = byteCode.Arguments[0].InferredType; | 
						|
						if (arg1Type != null && !arg1Type.IsValueType) goto case ILCode.Cne; | 
						|
						goto case ILCode.Cgt; | 
						|
					} | 
						|
					case ILCode.Cle_Un: { | 
						|
						// can also mean Equality, when used with object references | 
						|
						TypeReference arg1Type = byteCode.Arguments[0].InferredType; | 
						|
						if (arg1Type != null && !arg1Type.IsValueType) goto case ILCode.Ceq; | 
						|
						goto case ILCode.Cle; | 
						|
					} | 
						|
					case ILCode.Cle: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2); | 
						|
				case ILCode.Cge_Un: | 
						|
					case ILCode.Cge: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2); | 
						|
				case ILCode.Clt_Un: | 
						|
					case ILCode.Clt:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); | 
						|
					#endregion | 
						|
					#region Logical | 
						|
					case ILCode.LogicNot:   return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1); | 
						|
					case ILCode.LogicAnd:   return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ConditionalAnd, arg2); | 
						|
					case ILCode.LogicOr:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ConditionalOr, arg2); | 
						|
					case ILCode.TernaryOp:  return new Ast.ConditionalExpression() { Condition = arg1, TrueExpression = arg2, FalseExpression = arg3 }; | 
						|
					case ILCode.NullCoalescing: 	return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.NullCoalescing, arg2); | 
						|
					#endregion | 
						|
					#region Branch | 
						|
					case ILCode.Br:         return new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name); | 
						|
				case ILCode.Brtrue: | 
						|
					return new Ast.IfElseStatement() { | 
						|
						Condition = arg1, | 
						|
						TrueStatement = new BlockStatement() { | 
						|
							new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name) | 
						|
						} | 
						|
					}; | 
						|
					case ILCode.LoopOrSwitchBreak: return new Ast.BreakStatement(); | 
						|
					case ILCode.LoopContinue:      return new Ast.ContinueStatement(); | 
						|
					#endregion | 
						|
					#region Conversions | 
						|
				case ILCode.Conv_I1: | 
						|
				case ILCode.Conv_I2: | 
						|
				case ILCode.Conv_I4: | 
						|
				case ILCode.Conv_I8: | 
						|
				case ILCode.Conv_U1: | 
						|
				case ILCode.Conv_U2: | 
						|
				case ILCode.Conv_U4: | 
						|
				case ILCode.Conv_U8: | 
						|
				case ILCode.Conv_I: | 
						|
				case ILCode.Conv_U: | 
						|
					{ | 
						|
						// conversion was handled by Convert() function using the info from type analysis | 
						|
						CastExpression cast = arg1 as CastExpression; | 
						|
						if (cast != null) { | 
						|
							cast.AddAnnotation(AddCheckedBlocks.UncheckedAnnotation); | 
						|
						} | 
						|
						return arg1; | 
						|
					} | 
						|
				case ILCode.Conv_R4: | 
						|
				case ILCode.Conv_R8: | 
						|
				case ILCode.Conv_R_Un: // TODO | 
						|
					return arg1; | 
						|
				case ILCode.Conv_Ovf_I1: | 
						|
				case ILCode.Conv_Ovf_I2: | 
						|
				case ILCode.Conv_Ovf_I4: | 
						|
				case ILCode.Conv_Ovf_I8: | 
						|
				case ILCode.Conv_Ovf_U1: | 
						|
				case ILCode.Conv_Ovf_U2: | 
						|
				case ILCode.Conv_Ovf_U4: | 
						|
				case ILCode.Conv_Ovf_U8: | 
						|
				case ILCode.Conv_Ovf_I1_Un: | 
						|
				case ILCode.Conv_Ovf_I2_Un: | 
						|
				case ILCode.Conv_Ovf_I4_Un: | 
						|
				case ILCode.Conv_Ovf_I8_Un: | 
						|
				case ILCode.Conv_Ovf_U1_Un: | 
						|
				case ILCode.Conv_Ovf_U2_Un: | 
						|
				case ILCode.Conv_Ovf_U4_Un: | 
						|
				case ILCode.Conv_Ovf_U8_Un: | 
						|
				case ILCode.Conv_Ovf_I: | 
						|
				case ILCode.Conv_Ovf_U: | 
						|
				case ILCode.Conv_Ovf_I_Un: | 
						|
				case ILCode.Conv_Ovf_U_Un: | 
						|
					{ | 
						|
						// conversion was handled by Convert() function using the info from type analysis | 
						|
						CastExpression cast = arg1 as CastExpression; | 
						|
						if (cast != null) { | 
						|
							cast.AddAnnotation(AddCheckedBlocks.CheckedAnnotation); | 
						|
						} | 
						|
						return arg1; | 
						|
					} | 
						|
				case ILCode.Unbox_Any: | 
						|
					// unboxing does not require a cast if the argument was an isinst instruction | 
						|
					if (arg1 is AsExpression && byteCode.Arguments[0].Code == ILCode.Isinst && TypeAnalysis.IsSameType(operand as TypeReference, byteCode.Arguments[0].Operand as TypeReference)) | 
						|
						return arg1; | 
						|
					else | 
						|
						goto case ILCode.Castclass; | 
						|
				case ILCode.Castclass: | 
						|
					if ((byteCode.Arguments[0].InferredType != null && byteCode.Arguments[0].InferredType.IsGenericParameter) || ((Cecil.TypeReference)operand).IsGenericParameter) | 
						|
						return arg1.CastTo(new PrimitiveType("object")).CastTo(operandAsTypeRef); | 
						|
					else | 
						|
						return arg1.CastTo(operandAsTypeRef); | 
						|
				case ILCode.Isinst: | 
						|
					return arg1.CastAs(operandAsTypeRef); | 
						|
				case ILCode.Box: | 
						|
					return arg1; | 
						|
				case ILCode.Unbox: | 
						|
					return MakeRef(arg1.CastTo(operandAsTypeRef)); | 
						|
					#endregion | 
						|
					#region Indirect | 
						|
				case ILCode.Ldind_Ref: | 
						|
				case ILCode.Ldobj: | 
						|
					if (arg1 is DirectionExpression) | 
						|
						return ((DirectionExpression)arg1).Expression.Detach(); | 
						|
					else | 
						|
						return new UnaryOperatorExpression(UnaryOperatorType.Dereference, arg1); | 
						|
				case ILCode.Stind_Ref: | 
						|
				case ILCode.Stobj: | 
						|
					if (arg1 is DirectionExpression) | 
						|
						return new AssignmentExpression(((DirectionExpression)arg1).Expression.Detach(), arg2); | 
						|
					else | 
						|
						return new AssignmentExpression(new UnaryOperatorExpression(UnaryOperatorType.Dereference, arg1), arg2); | 
						|
					#endregion | 
						|
				case ILCode.Arglist: | 
						|
					return new UndocumentedExpression { UndocumentedExpressionType = UndocumentedExpressionType.ArgListAccess }; | 
						|
					case ILCode.Break:    return InlineAssembly(byteCode, args); | 
						|
				case ILCode.Call: | 
						|
				case ILCode.CallGetter: | 
						|
				case ILCode.CallSetter: | 
						|
					return TransformCall(false, byteCode, args); | 
						|
				case ILCode.Callvirt: | 
						|
				case ILCode.CallvirtGetter: | 
						|
				case ILCode.CallvirtSetter: | 
						|
					return TransformCall(true, byteCode,  args); | 
						|
					case ILCode.Ldftn: { | 
						|
						Cecil.MethodReference cecilMethod = ((MethodReference)operand); | 
						|
						var expr = new Ast.IdentifierExpression(cecilMethod.Name); | 
						|
						expr.TypeArguments.AddRange(ConvertTypeArguments(cecilMethod)); | 
						|
						expr.AddAnnotation(cecilMethod); | 
						|
						return new IdentifierExpression("ldftn").Invoke(expr) | 
						|
							.WithAnnotation(new Transforms.DelegateConstruction.Annotation(false)); | 
						|
					} | 
						|
					case ILCode.Ldvirtftn: { | 
						|
						Cecil.MethodReference cecilMethod = ((MethodReference)operand); | 
						|
						var expr = new Ast.IdentifierExpression(cecilMethod.Name); | 
						|
						expr.TypeArguments.AddRange(ConvertTypeArguments(cecilMethod)); | 
						|
						expr.AddAnnotation(cecilMethod); | 
						|
						return new IdentifierExpression("ldvirtftn").Invoke(expr) | 
						|
							.WithAnnotation(new Transforms.DelegateConstruction.Annotation(true)); | 
						|
					} | 
						|
					case ILCode.Calli:       return InlineAssembly(byteCode, args); | 
						|
					case ILCode.Ckfinite:    return InlineAssembly(byteCode, args); | 
						|
					case ILCode.Constrained: return InlineAssembly(byteCode, args); | 
						|
					case ILCode.Cpblk:       return InlineAssembly(byteCode, args); | 
						|
					case ILCode.Cpobj:       return InlineAssembly(byteCode, args); | 
						|
					case ILCode.Dup:         return arg1; | 
						|
					case ILCode.Endfilter:   return InlineAssembly(byteCode, args); | 
						|
					case ILCode.Endfinally:  return null; | 
						|
					case ILCode.Initblk:     return InlineAssembly(byteCode, args); | 
						|
					case ILCode.Initobj:      return InlineAssembly(byteCode, args); | 
						|
				case ILCode.DefaultValue: | 
						|
					return MakeDefaultValue((TypeReference)operand); | 
						|
					case ILCode.Jmp: return InlineAssembly(byteCode, args); | 
						|
				case ILCode.Ldc_I4: | 
						|
					return AstBuilder.MakePrimitive((int)operand, byteCode.InferredType); | 
						|
				case ILCode.Ldc_I8: | 
						|
					return AstBuilder.MakePrimitive((long)operand, byteCode.InferredType); | 
						|
				case ILCode.Ldc_R4: | 
						|
				case ILCode.Ldc_R8: | 
						|
				case ILCode.Ldc_Decimal: | 
						|
					return new Ast.PrimitiveExpression(operand); | 
						|
				case ILCode.Ldfld: | 
						|
					if (arg1 is DirectionExpression) | 
						|
						arg1 = ((DirectionExpression)arg1).Expression.Detach(); | 
						|
					return arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand); | 
						|
				case ILCode.Ldsfld: | 
						|
					return AstBuilder.ConvertType(((FieldReference)operand).DeclaringType) | 
						|
						.Member(((FieldReference)operand).Name).WithAnnotation(operand); | 
						|
				case ILCode.Stfld: | 
						|
					if (arg1 is DirectionExpression) | 
						|
						arg1 = ((DirectionExpression)arg1).Expression.Detach(); | 
						|
					return new AssignmentExpression(arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand), arg2); | 
						|
				case ILCode.Stsfld: | 
						|
					return new AssignmentExpression( | 
						|
						AstBuilder.ConvertType(((FieldReference)operand).DeclaringType) | 
						|
						.Member(((FieldReference)operand).Name).WithAnnotation(operand), | 
						|
						arg1); | 
						|
				case ILCode.Ldflda: | 
						|
					if (arg1 is DirectionExpression) | 
						|
						arg1 = ((DirectionExpression)arg1).Expression.Detach(); | 
						|
					return MakeRef(arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand)); | 
						|
				case ILCode.Ldsflda: | 
						|
					return MakeRef( | 
						|
						AstBuilder.ConvertType(((FieldReference)operand).DeclaringType) | 
						|
						.Member(((FieldReference)operand).Name).WithAnnotation(operand)); | 
						|
					case ILCode.Ldloc: { | 
						|
						ILVariable v = (ILVariable)operand; | 
						|
						if (!v.IsParameter) | 
						|
							localVariablesToDefine.Add((ILVariable)operand); | 
						|
						Expression expr; | 
						|
						if (v.IsParameter && v.OriginalParameter.Index < 0) | 
						|
							expr = new ThisReferenceExpression(); | 
						|
						else | 
						|
							expr = new Ast.IdentifierExpression(((ILVariable)operand).Name).WithAnnotation(operand); | 
						|
						return v.IsParameter && v.Type is ByReferenceType ? MakeRef(expr) : expr; | 
						|
					} | 
						|
					case ILCode.Ldloca: { | 
						|
						ILVariable v = (ILVariable)operand; | 
						|
						if (v.IsParameter && v.OriginalParameter.Index < 0) | 
						|
							return MakeRef(new ThisReferenceExpression()); | 
						|
						if (!v.IsParameter) | 
						|
							localVariablesToDefine.Add((ILVariable)operand); | 
						|
						return MakeRef(new Ast.IdentifierExpression(((ILVariable)operand).Name).WithAnnotation(operand)); | 
						|
					} | 
						|
					case ILCode.Ldnull: return new Ast.NullReferenceExpression(); | 
						|
					case ILCode.Ldstr:  return new Ast.PrimitiveExpression(operand); | 
						|
				case ILCode.Ldtoken: | 
						|
					if (operand is Cecil.TypeReference) { | 
						|
						return AstBuilder.CreateTypeOfExpression((TypeReference)operand).Member("TypeHandle"); | 
						|
					} else { | 
						|
						Expression referencedEntity; | 
						|
						string loadName; | 
						|
						string handleName; | 
						|
						if (operand is Cecil.FieldReference) { | 
						|
							loadName = "fieldof"; | 
						|
							handleName = "FieldHandle"; | 
						|
							FieldReference fr = (FieldReference)operand; | 
						|
							referencedEntity = AstBuilder.ConvertType(fr.DeclaringType).Member(fr.Name).WithAnnotation(fr); | 
						|
						} else if (operand is Cecil.MethodReference) { | 
						|
							loadName = "methodof"; | 
						|
							handleName = "MethodHandle"; | 
						|
							MethodReference mr = (MethodReference)operand; | 
						|
							var methodParameters = mr.Parameters.Select(p => new TypeReferenceExpression(AstBuilder.ConvertType(p.ParameterType))); | 
						|
							referencedEntity = AstBuilder.ConvertType(mr.DeclaringType).Invoke(mr.Name, methodParameters).WithAnnotation(mr); | 
						|
						} else { | 
						|
							loadName = "ldtoken"; | 
						|
							handleName = "Handle"; | 
						|
							referencedEntity = new IdentifierExpression(FormatByteCodeOperand(byteCode.Operand)); | 
						|
						} | 
						|
						return new IdentifierExpression(loadName).Invoke(referencedEntity).WithAnnotation(new LdTokenAnnotation()).Member(handleName); | 
						|
					} | 
						|
					case ILCode.Leave:    return new GotoStatement() { Label = ((ILLabel)operand).Name }; | 
						|
				case ILCode.Localloc: | 
						|
					{ | 
						|
						PointerType ptrType = byteCode.InferredType as PointerType; | 
						|
						TypeReference type; | 
						|
						if (ptrType != null) { | 
						|
							type = ptrType.ElementType; | 
						|
						} else { | 
						|
							type = typeSystem.Byte; | 
						|
						} | 
						|
						return new StackAllocExpression { | 
						|
							Type = AstBuilder.ConvertType(type), | 
						|
							CountExpression = DivideBySize(arg1, type) | 
						|
						}; | 
						|
					} | 
						|
				case ILCode.Mkrefany: | 
						|
					{ | 
						|
						DirectionExpression dir = arg1 as DirectionExpression; | 
						|
						if (dir != null) { | 
						|
							return new UndocumentedExpression { | 
						|
								UndocumentedExpressionType = UndocumentedExpressionType.MakeRef, | 
						|
								Arguments = { dir.Expression.Detach() } | 
						|
							}; | 
						|
						} else { | 
						|
							return InlineAssembly(byteCode, args); | 
						|
						} | 
						|
					} | 
						|
				case ILCode.Refanytype: | 
						|
					return new UndocumentedExpression { | 
						|
						UndocumentedExpressionType = UndocumentedExpressionType.RefType, | 
						|
						Arguments = { arg1 } | 
						|
					}.Member("TypeHandle"); | 
						|
				case ILCode.Refanyval: | 
						|
					return MakeRef( | 
						|
						new UndocumentedExpression { | 
						|
							UndocumentedExpressionType = UndocumentedExpressionType.RefValue, | 
						|
							Arguments = { arg1, new TypeReferenceExpression(operandAsTypeRef) } | 
						|
						}); | 
						|
					case ILCode.Newobj: { | 
						|
						Cecil.TypeReference declaringType = ((MethodReference)operand).DeclaringType; | 
						|
						if (declaringType is ArrayType) { | 
						|
							ComposedType ct = AstBuilder.ConvertType((ArrayType)declaringType) as ComposedType; | 
						|
							if (ct != null && ct.ArraySpecifiers.Count >= 1) { | 
						|
								var ace = new Ast.ArrayCreateExpression(); | 
						|
								ct.ArraySpecifiers.First().Remove(); | 
						|
								ct.ArraySpecifiers.MoveTo(ace.AdditionalArraySpecifiers); | 
						|
								ace.Type = ct; | 
						|
								ace.Arguments.AddRange(args); | 
						|
								return ace; | 
						|
							} | 
						|
						} | 
						|
						if (declaringType.IsAnonymousType()) { | 
						|
							MethodDefinition ctor = ((MethodReference)operand).Resolve(); | 
						|
							if (methodDef != null) { | 
						|
								AnonymousTypeCreateExpression atce = new AnonymousTypeCreateExpression(); | 
						|
								if (CanInferAnonymousTypePropertyNamesFromArguments(args, ctor.Parameters)) { | 
						|
									atce.Initializers.AddRange(args); | 
						|
								} else { | 
						|
									for (int i = 0; i < args.Count; i++) { | 
						|
										atce.Initializers.Add( | 
						|
											new NamedExpression { | 
						|
												Name = ctor.Parameters[i].Name, | 
						|
												Expression = args[i] | 
						|
											}); | 
						|
									} | 
						|
								} | 
						|
								return atce; | 
						|
							} | 
						|
						} | 
						|
						var oce = new Ast.ObjectCreateExpression(); | 
						|
						oce.Type = AstBuilder.ConvertType(declaringType); | 
						|
						oce.Arguments.AddRange(args); | 
						|
						return oce.WithAnnotation(operand); | 
						|
					} | 
						|
					case ILCode.No: return InlineAssembly(byteCode, args); | 
						|
					case ILCode.Nop: return null; | 
						|
					case ILCode.Pop: return arg1; | 
						|
					case ILCode.Readonly: return InlineAssembly(byteCode, args); | 
						|
				case ILCode.Ret: | 
						|
					if (methodDef.ReturnType.FullName != "System.Void") { | 
						|
						return new Ast.ReturnStatement { Expression = arg1 }; | 
						|
					} else { | 
						|
						return new Ast.ReturnStatement(); | 
						|
					} | 
						|
					case ILCode.Rethrow: return new Ast.ThrowStatement(); | 
						|
					case ILCode.Sizeof:  return new Ast.SizeOfExpression { Type = operandAsTypeRef }; | 
						|
					case ILCode.Stloc: { | 
						|
						ILVariable locVar = (ILVariable)operand; | 
						|
						if (!locVar.IsParameter) | 
						|
							localVariablesToDefine.Add(locVar); | 
						|
						return new Ast.AssignmentExpression(new Ast.IdentifierExpression(locVar.Name).WithAnnotation(locVar), arg1); | 
						|
					} | 
						|
					case ILCode.Switch: return InlineAssembly(byteCode, args); | 
						|
					case ILCode.Tail: return InlineAssembly(byteCode, args); | 
						|
					case ILCode.Throw: return new Ast.ThrowStatement { Expression = arg1 }; | 
						|
					case ILCode.Unaligned: return InlineAssembly(byteCode, args); | 
						|
					case ILCode.Volatile: return InlineAssembly(byteCode, args); | 
						|
				case ILCode.YieldBreak: | 
						|
					return new Ast.YieldBreakStatement(); | 
						|
				case ILCode.YieldReturn: | 
						|
					return new Ast.YieldReturnStatement { Expression = arg1 }; | 
						|
				case ILCode.InitObject: | 
						|
				case ILCode.InitCollection: | 
						|
					{ | 
						|
						ArrayInitializerExpression initializer = new ArrayInitializerExpression(); | 
						|
						for (int i = 1; i < args.Count; i++) { | 
						|
							Match m = objectInitializerPattern.Match(args[i]); | 
						|
							if (m.Success) { | 
						|
								MemberReferenceExpression mre = m.Get<MemberReferenceExpression>("left").Single(); | 
						|
								initializer.Elements.Add( | 
						|
									new NamedExpression { | 
						|
										Name = mre.MemberName, | 
						|
										Expression = m.Get<Expression>("right").Single().Detach() | 
						|
									}.CopyAnnotationsFrom(mre)); | 
						|
							} else { | 
						|
								m = collectionInitializerPattern.Match(args[i]); | 
						|
								if (m.Success) { | 
						|
									if (m.Get("arg").Count() == 1) { | 
						|
										initializer.Elements.Add(m.Get<Expression>("arg").Single().Detach()); | 
						|
									} else { | 
						|
										ArrayInitializerExpression argList = new ArrayInitializerExpression(); | 
						|
										foreach (var expr in m.Get<Expression>("arg")) { | 
						|
											argList.Elements.Add(expr.Detach()); | 
						|
										} | 
						|
										initializer.Elements.Add(argList); | 
						|
									} | 
						|
								} else { | 
						|
									initializer.Elements.Add(args[i]); | 
						|
								} | 
						|
							} | 
						|
						} | 
						|
						ObjectCreateExpression oce = arg1 as ObjectCreateExpression; | 
						|
						DefaultValueExpression dve = arg1 as DefaultValueExpression; | 
						|
						if (oce != null) { | 
						|
							oce.Initializer = initializer; | 
						|
							return oce; | 
						|
						} else if (dve != null) { | 
						|
							oce = new ObjectCreateExpression(dve.Type.Detach()); | 
						|
							oce.CopyAnnotationsFrom(dve); | 
						|
							oce.Initializer = initializer; | 
						|
							return oce; | 
						|
						} else { | 
						|
							return new AssignmentExpression(arg1, initializer); | 
						|
						} | 
						|
					} | 
						|
				case ILCode.InitializedObject: | 
						|
					return new InitializedObjectExpression(); | 
						|
				case ILCode.Wrap: | 
						|
					return arg1.WithAnnotation(PushNegation.LiftedOperatorAnnotation); | 
						|
				case ILCode.AddressOf: | 
						|
					return MakeRef(arg1); | 
						|
				case ILCode.ExpressionTreeParameterDeclarations: | 
						|
					args[args.Count - 1].AddAnnotation(new ParameterDeclarationAnnotation(byteCode)); | 
						|
					return args[args.Count - 1]; | 
						|
				case ILCode.Await: | 
						|
					return new UnaryOperatorExpression(UnaryOperatorType.Await, UnpackDirectionExpression(arg1)); | 
						|
				case ILCode.NullableOf: | 
						|
				case ILCode.ValueOf:  | 
						|
					return arg1; | 
						|
				default: | 
						|
					throw new Exception("Unknown OpCode: " + byteCode.Code); | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		internal static bool CanInferAnonymousTypePropertyNamesFromArguments(IList<Expression> args, IList<ParameterDefinition> parameters) | 
						|
		{ | 
						|
			for (int i = 0; i < args.Count; i++) { | 
						|
				string inferredName; | 
						|
				if (args[i] is IdentifierExpression) | 
						|
					inferredName = ((IdentifierExpression)args[i]).Identifier; | 
						|
				else if (args[i] is MemberReferenceExpression) | 
						|
					inferredName = ((MemberReferenceExpression)args[i]).MemberName; | 
						|
				else | 
						|
					inferredName = null; | 
						|
				 | 
						|
				if (inferredName != parameters[i].Name) { | 
						|
					return false; | 
						|
				} | 
						|
			} | 
						|
			return true; | 
						|
		} | 
						|
		 | 
						|
		static readonly AstNode objectInitializerPattern = new AssignmentExpression( | 
						|
			new MemberReferenceExpression { | 
						|
				Target = new InitializedObjectExpression(), | 
						|
				MemberName = Pattern.AnyString | 
						|
			}.WithName("left"), | 
						|
			new AnyNode("right") | 
						|
		); | 
						|
		 | 
						|
		static readonly AstNode collectionInitializerPattern = new InvocationExpression { | 
						|
			Target = new MemberReferenceExpression { | 
						|
				Target = new InitializedObjectExpression(), | 
						|
				MemberName = "Add" | 
						|
			}, | 
						|
			Arguments = { new Repeat(new AnyNode("arg")) } | 
						|
		}; | 
						|
		 | 
						|
		sealed class InitializedObjectExpression : IdentifierExpression | 
						|
		{ | 
						|
			public InitializedObjectExpression() : base("__initialized_object__") {} | 
						|
			 | 
						|
			protected override bool DoMatch(AstNode other, Match match) | 
						|
			{ | 
						|
				return other is InitializedObjectExpression; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		/// <summary> | 
						|
		/// Divides expr by the size of 'type'. | 
						|
		/// </summary> | 
						|
		Expression DivideBySize(Expression expr, TypeReference type) | 
						|
		{ | 
						|
			CastExpression cast = expr as CastExpression; | 
						|
			if (cast != null && cast.Type is PrimitiveType && ((PrimitiveType)cast.Type).Keyword == "int") | 
						|
				expr = cast.Expression.Detach(); | 
						|
			 | 
						|
			Expression sizeOfExpression; | 
						|
			switch (TypeAnalysis.GetInformationAmount(type)) { | 
						|
				case 1: | 
						|
				case 8: | 
						|
					sizeOfExpression = new PrimitiveExpression(1); | 
						|
					break; | 
						|
				case 16: | 
						|
					sizeOfExpression = new PrimitiveExpression(2); | 
						|
					break; | 
						|
				case 32: | 
						|
					sizeOfExpression = new PrimitiveExpression(4); | 
						|
					break; | 
						|
				case 64: | 
						|
					sizeOfExpression = new PrimitiveExpression(8); | 
						|
					break; | 
						|
				default: | 
						|
					sizeOfExpression = new SizeOfExpression { Type = AstBuilder.ConvertType(type) }; | 
						|
					break; | 
						|
			} | 
						|
			 | 
						|
			BinaryOperatorExpression boe = expr as BinaryOperatorExpression; | 
						|
			if (boe != null && boe.Operator == BinaryOperatorType.Multiply && sizeOfExpression.IsMatch(boe.Right)) | 
						|
				return boe.Left.Detach(); | 
						|
			 | 
						|
			if (sizeOfExpression.IsMatch(expr)) | 
						|
				return new PrimitiveExpression(1); | 
						|
			 | 
						|
			return new BinaryOperatorExpression(expr, BinaryOperatorType.Divide, sizeOfExpression); | 
						|
		} | 
						|
		 | 
						|
		Expression MakeDefaultValue(TypeReference type) | 
						|
		{ | 
						|
			TypeDefinition typeDef = type.Resolve(); | 
						|
			if (typeDef != null) { | 
						|
				if (TypeAnalysis.IsIntegerOrEnum(typeDef)) | 
						|
					return AstBuilder.MakePrimitive(0, typeDef); | 
						|
				else if (!typeDef.IsValueType) | 
						|
					return new NullReferenceExpression(); | 
						|
				switch (typeDef.FullName) { | 
						|
					case "System.Nullable`1": | 
						|
						return new NullReferenceExpression(); | 
						|
					case "System.Single": | 
						|
						return new PrimitiveExpression(0f); | 
						|
					case "System.Double": | 
						|
						return new PrimitiveExpression(0.0); | 
						|
					case "System.Decimal": | 
						|
						return new PrimitiveExpression(0m); | 
						|
				} | 
						|
			} | 
						|
			return new DefaultValueExpression { Type = AstBuilder.ConvertType(type) }; | 
						|
		} | 
						|
		 | 
						|
		AstNode TransformCall(bool isVirtual, ILExpression byteCode, List<Ast.Expression> args) | 
						|
		{ | 
						|
			Cecil.MethodReference cecilMethod = (MethodReference)byteCode.Operand; | 
						|
			Cecil.MethodDefinition cecilMethodDef = cecilMethod.Resolve(); | 
						|
			Ast.Expression target; | 
						|
			List<Ast.Expression> methodArgs = new List<Ast.Expression>(args); | 
						|
			if (cecilMethod.HasThis) { | 
						|
				target = methodArgs[0]; | 
						|
				methodArgs.RemoveAt(0); | 
						|
				 | 
						|
				// Unpack any DirectionExpression that is used as target for the call | 
						|
				// (calling methods on value types implicitly passes the first argument by reference) | 
						|
				target = UnpackDirectionExpression(target); | 
						|
				 | 
						|
				if (cecilMethodDef != null) { | 
						|
					// convert null.ToLower() to ((string)null).ToLower() | 
						|
					if (target is NullReferenceExpression) | 
						|
						target = target.CastTo(AstBuilder.ConvertType(cecilMethod.DeclaringType)); | 
						|
					 | 
						|
					if (cecilMethodDef.DeclaringType.IsInterface) { | 
						|
						TypeReference tr = byteCode.Arguments[0].InferredType; | 
						|
						if (tr != null) { | 
						|
							TypeDefinition td = tr.Resolve(); | 
						|
							if (td != null && !td.IsInterface) { | 
						|
								// Calling an interface method on a non-interface object: | 
						|
								// we need to introduce an explicit cast | 
						|
								target = target.CastTo(AstBuilder.ConvertType(cecilMethod.DeclaringType)); | 
						|
							} | 
						|
						} | 
						|
					} | 
						|
				} | 
						|
			} else { | 
						|
				target = new TypeReferenceExpression { Type = AstBuilder.ConvertType(cecilMethod.DeclaringType) }; | 
						|
			} | 
						|
			if (target is ThisReferenceExpression && !isVirtual) { | 
						|
				// a non-virtual call on "this" might be a "base"-call. | 
						|
				if (cecilMethod.DeclaringType.GetElementType() != methodDef.DeclaringType) { | 
						|
					// If we're not calling a method in the current class; we must be calling one in the base class. | 
						|
					target = new BaseReferenceExpression(); | 
						|
				} | 
						|
			} | 
						|
			 | 
						|
			if (cecilMethod.Name == ".ctor" && cecilMethod.DeclaringType.IsValueType) { | 
						|
				// On value types, the constructor can be called. | 
						|
				// This is equivalent to 'target = new ValueType(args);'. | 
						|
				ObjectCreateExpression oce = new ObjectCreateExpression(); | 
						|
				oce.Type = AstBuilder.ConvertType(cecilMethod.DeclaringType); | 
						|
				oce.AddAnnotation(cecilMethod); | 
						|
				AdjustArgumentsForMethodCall(cecilMethod, methodArgs); | 
						|
				oce.Arguments.AddRange(methodArgs); | 
						|
				return new AssignmentExpression(target, oce); | 
						|
			} | 
						|
			 | 
						|
			if (cecilMethod.Name == "Get" && cecilMethod.DeclaringType is ArrayType && methodArgs.Count > 1) { | 
						|
				return target.Indexer(methodArgs); | 
						|
			} else if (cecilMethod.Name == "Set" && cecilMethod.DeclaringType is ArrayType && methodArgs.Count > 2) { | 
						|
				return new AssignmentExpression(target.Indexer(methodArgs.GetRange(0, methodArgs.Count - 1)), methodArgs.Last()); | 
						|
			} | 
						|
			 | 
						|
			// Test whether the method is an accessor: | 
						|
			if (cecilMethodDef != null) { | 
						|
				if (cecilMethodDef.IsGetter && methodArgs.Count == 0) { | 
						|
					foreach (var prop in cecilMethodDef.DeclaringType.Properties) { | 
						|
						if (prop.GetMethod == cecilMethodDef) | 
						|
							return target.Member(prop.Name).WithAnnotation(prop).WithAnnotation(cecilMethod); | 
						|
					} | 
						|
				} else if (cecilMethodDef.IsGetter) { // with parameters | 
						|
					PropertyDefinition indexer = GetIndexer(cecilMethodDef); | 
						|
					if (indexer != null) | 
						|
						return target.Indexer(methodArgs).WithAnnotation(indexer).WithAnnotation(cecilMethod); | 
						|
				} else if (cecilMethodDef.IsSetter && methodArgs.Count == 1) { | 
						|
					foreach (var prop in cecilMethodDef.DeclaringType.Properties) { | 
						|
						if (prop.SetMethod == cecilMethodDef) | 
						|
							return new Ast.AssignmentExpression(target.Member(prop.Name).WithAnnotation(prop).WithAnnotation(cecilMethod), methodArgs[0]); | 
						|
					} | 
						|
				} else if (cecilMethodDef.IsSetter && methodArgs.Count > 1) { | 
						|
					PropertyDefinition indexer = GetIndexer(cecilMethodDef); | 
						|
					if (indexer != null) | 
						|
						return new AssignmentExpression( | 
						|
							target.Indexer(methodArgs.GetRange(0, methodArgs.Count - 1)).WithAnnotation(indexer).WithAnnotation(cecilMethod), | 
						|
							methodArgs[methodArgs.Count - 1] | 
						|
						); | 
						|
				} else if (cecilMethodDef.IsAddOn && methodArgs.Count == 1) { | 
						|
					foreach (var ev in cecilMethodDef.DeclaringType.Events) { | 
						|
						if (ev.AddMethod == cecilMethodDef) { | 
						|
							return new Ast.AssignmentExpression { | 
						|
								Left = target.Member(ev.Name).WithAnnotation(ev).WithAnnotation(cecilMethod), | 
						|
								Operator = AssignmentOperatorType.Add, | 
						|
								Right = methodArgs[0] | 
						|
							}; | 
						|
						} | 
						|
					} | 
						|
				} else if (cecilMethodDef.IsRemoveOn && methodArgs.Count == 1) { | 
						|
					foreach (var ev in cecilMethodDef.DeclaringType.Events) { | 
						|
						if (ev.RemoveMethod == cecilMethodDef) { | 
						|
							return new Ast.AssignmentExpression { | 
						|
								Left = target.Member(ev.Name).WithAnnotation(ev).WithAnnotation(cecilMethod), | 
						|
								Operator = AssignmentOperatorType.Subtract, | 
						|
								Right = methodArgs[0] | 
						|
							}; | 
						|
						} | 
						|
					} | 
						|
				} else if (cecilMethodDef.Name == "Invoke" && cecilMethodDef.DeclaringType.BaseType != null && cecilMethodDef.DeclaringType.BaseType.FullName == "System.MulticastDelegate") { | 
						|
					AdjustArgumentsForMethodCall(cecilMethod, methodArgs); | 
						|
					return target.Invoke(methodArgs).WithAnnotation(cecilMethod); | 
						|
				} | 
						|
			} | 
						|
			// Default invocation | 
						|
			AdjustArgumentsForMethodCall(cecilMethodDef ?? cecilMethod, methodArgs); | 
						|
			return target.Invoke(cecilMethod.Name, ConvertTypeArguments(cecilMethod), methodArgs).WithAnnotation(cecilMethod); | 
						|
		} | 
						|
		 | 
						|
		static Expression UnpackDirectionExpression(Expression target) | 
						|
		{ | 
						|
			if (target is DirectionExpression) { | 
						|
				return ((DirectionExpression)target).Expression.Detach(); | 
						|
			} else { | 
						|
				return target; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		static void AdjustArgumentsForMethodCall(MethodReference cecilMethod, List<Expression> methodArgs) | 
						|
		{ | 
						|
			// Convert 'ref' into 'out' where necessary | 
						|
			for (int i = 0; i < methodArgs.Count && i < cecilMethod.Parameters.Count; i++) { | 
						|
				DirectionExpression dir = methodArgs[i] as DirectionExpression; | 
						|
				ParameterDefinition p = cecilMethod.Parameters[i]; | 
						|
				if (dir != null && p.IsOut && !p.IsIn) | 
						|
					dir.FieldDirection = FieldDirection.Out; | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		internal static PropertyDefinition GetIndexer(MethodDefinition cecilMethodDef) | 
						|
		{ | 
						|
			TypeDefinition typeDef = cecilMethodDef.DeclaringType; | 
						|
			string indexerName = null; | 
						|
			foreach (CustomAttribute ca in typeDef.CustomAttributes) { | 
						|
				if (ca.Constructor.FullName == "System.Void System.Reflection.DefaultMemberAttribute::.ctor(System.String)") { | 
						|
					indexerName = ca.ConstructorArguments.Single().Value as string; | 
						|
					break; | 
						|
				} | 
						|
			} | 
						|
			if (indexerName == null) | 
						|
				return null; | 
						|
			foreach (PropertyDefinition prop in typeDef.Properties) { | 
						|
				if (prop.Name == indexerName) { | 
						|
					if (prop.GetMethod == cecilMethodDef || prop.SetMethod == cecilMethodDef) | 
						|
						return prop; | 
						|
				} | 
						|
			} | 
						|
			return null; | 
						|
		} | 
						|
		 | 
						|
		#if DEBUG | 
						|
		static readonly ConcurrentDictionary<ILCode, int> unhandledOpcodes = new ConcurrentDictionary<ILCode, int>(); | 
						|
		#endif | 
						|
		 | 
						|
		[Conditional("DEBUG")] | 
						|
		public static void ClearUnhandledOpcodes() | 
						|
		{ | 
						|
			#if DEBUG | 
						|
			unhandledOpcodes.Clear(); | 
						|
			#endif | 
						|
		} | 
						|
		 | 
						|
		[Conditional("DEBUG")] | 
						|
		public static void PrintNumberOfUnhandledOpcodes() | 
						|
		{ | 
						|
			#if DEBUG | 
						|
			foreach (var pair in unhandledOpcodes) { | 
						|
				Debug.WriteLine("AddMethodBodyBuilder unhandled opcode: {1}x {0}", pair.Key, pair.Value); | 
						|
			} | 
						|
			#endif | 
						|
		} | 
						|
		 | 
						|
		static Expression InlineAssembly(ILExpression byteCode, List<Ast.Expression> args) | 
						|
		{ | 
						|
			#if DEBUG | 
						|
			unhandledOpcodes.AddOrUpdate(byteCode.Code, c => 1, (c, n) => n+1); | 
						|
			#endif | 
						|
			// Output the operand of the unknown IL code as well | 
						|
			if (byteCode.Operand != null) { | 
						|
				args.Insert(0, new IdentifierExpression(FormatByteCodeOperand(byteCode.Operand))); | 
						|
			} | 
						|
			return new IdentifierExpression(byteCode.Code.GetName()).Invoke(args); | 
						|
		} | 
						|
		 | 
						|
		static string FormatByteCodeOperand(object operand) | 
						|
		{ | 
						|
			if (operand == null) { | 
						|
				return string.Empty; | 
						|
				//} else if (operand is ILExpression) { | 
						|
				//	return string.Format("IL_{0:X2}", ((ILExpression)operand).Offset); | 
						|
			} else if (operand is MethodReference) { | 
						|
				return ((MethodReference)operand).Name + "()"; | 
						|
			} else if (operand is Cecil.TypeReference) { | 
						|
				return ((Cecil.TypeReference)operand).FullName; | 
						|
			} else if (operand is VariableDefinition) { | 
						|
				return ((VariableDefinition)operand).Name; | 
						|
			} else if (operand is ParameterDefinition) { | 
						|
				return ((ParameterDefinition)operand).Name; | 
						|
			} else if (operand is FieldReference) { | 
						|
				return ((FieldReference)operand).Name; | 
						|
			} else if (operand is string) { | 
						|
				return "\"" + operand + "\""; | 
						|
			} else if (operand is int) { | 
						|
				return operand.ToString(); | 
						|
			} else { | 
						|
				return operand.ToString(); | 
						|
			} | 
						|
		} | 
						|
		 | 
						|
		static IEnumerable<AstType> ConvertTypeArguments(MethodReference cecilMethod) | 
						|
		{ | 
						|
			GenericInstanceMethod g = cecilMethod as GenericInstanceMethod; | 
						|
			if (g == null) | 
						|
				return null; | 
						|
			if (g.GenericArguments.Any(ta => ta.ContainsAnonymousType())) | 
						|
				return null; | 
						|
			return g.GenericArguments.Select(t => AstBuilder.ConvertType(t)); | 
						|
		} | 
						|
		 | 
						|
		static Ast.DirectionExpression MakeRef(Ast.Expression expr) | 
						|
		{ | 
						|
			return new DirectionExpression { Expression = expr, FieldDirection = FieldDirection.Ref }; | 
						|
		} | 
						|
		 | 
						|
		Ast.Expression Convert(Ast.Expression expr, Cecil.TypeReference actualType, Cecil.TypeReference reqType) | 
						|
		{ | 
						|
			if (actualType == null || reqType == null || TypeAnalysis.IsSameType(actualType, reqType)) { | 
						|
				return expr; | 
						|
			} else if (actualType is ByReferenceType && reqType is PointerType && expr is DirectionExpression) { | 
						|
				return Convert( | 
						|
					new UnaryOperatorExpression(UnaryOperatorType.AddressOf, ((DirectionExpression)expr).Expression.Detach()), | 
						|
					new PointerType(((ByReferenceType)actualType).ElementType), | 
						|
					reqType); | 
						|
			} else if (actualType is PointerType && reqType is ByReferenceType) { | 
						|
				expr = Convert(expr, actualType, new PointerType(((ByReferenceType)reqType).ElementType)); | 
						|
				return new DirectionExpression { | 
						|
					FieldDirection = FieldDirection.Ref, | 
						|
					Expression = new UnaryOperatorExpression(UnaryOperatorType.Dereference, expr) | 
						|
				}; | 
						|
			} else if (actualType is PointerType && reqType is PointerType) { | 
						|
				if (actualType.FullName != reqType.FullName) | 
						|
					return expr.CastTo(AstBuilder.ConvertType(reqType)); | 
						|
				else | 
						|
					return expr; | 
						|
			} else { | 
						|
				bool actualIsIntegerOrEnum = TypeAnalysis.IsIntegerOrEnum(actualType); | 
						|
				bool requiredIsIntegerOrEnum = TypeAnalysis.IsIntegerOrEnum(reqType); | 
						|
				 | 
						|
				if (TypeAnalysis.IsBoolean(reqType)) { | 
						|
					if (TypeAnalysis.IsBoolean(actualType)) | 
						|
						return expr; | 
						|
					if (actualIsIntegerOrEnum) { | 
						|
						return new BinaryOperatorExpression(expr, BinaryOperatorType.InEquality, AstBuilder.MakePrimitive(0, actualType)); | 
						|
					} else { | 
						|
						return new BinaryOperatorExpression(expr, BinaryOperatorType.InEquality, new NullReferenceExpression()); | 
						|
					} | 
						|
				} | 
						|
				if (TypeAnalysis.IsBoolean(actualType) && requiredIsIntegerOrEnum) { | 
						|
					return new ConditionalExpression { | 
						|
						Condition = expr, | 
						|
						TrueExpression = AstBuilder.MakePrimitive(1, reqType), | 
						|
						FalseExpression = AstBuilder.MakePrimitive(0, reqType) | 
						|
					}; | 
						|
				} | 
						|
 | 
						|
				if (expr is PrimitiveExpression && !requiredIsIntegerOrEnum && TypeAnalysis.IsEnum(actualType)) | 
						|
				{ | 
						|
					return expr.CastTo(AstBuilder.ConvertType(actualType)); | 
						|
				} | 
						|
				 | 
						|
				bool actualIsPrimitiveType = actualIsIntegerOrEnum | 
						|
					|| actualType.MetadataType == MetadataType.Single || actualType.MetadataType == MetadataType.Double; | 
						|
				bool requiredIsPrimitiveType = requiredIsIntegerOrEnum | 
						|
					|| reqType.MetadataType == MetadataType.Single || reqType.MetadataType == MetadataType.Double; | 
						|
				if (actualIsPrimitiveType && requiredIsPrimitiveType) { | 
						|
					return expr.CastTo(AstBuilder.ConvertType(reqType)); | 
						|
				} | 
						|
				return expr; | 
						|
			} | 
						|
		} | 
						|
	} | 
						|
}
 | 
						|
 |