AstNode TransformByteCode(ILExpression byteCode) { ILCode opCode = byteCode.Code; object operand = byteCode.Operand; AstType operandAsTypeRef = AstBuilder.ConvertType(operand as Cecil.TypeReference); ILExpression operandAsByteCode = operand as ILExpression; // Do branches first because TransformExpressionArguments does not work on arguments that are branches themselfs // TODO: We should probably have virtual instructions for these and not abuse branch codes as expressions switch(opCode) { case ILCode.Br: return new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name); case ILCode.Brfalse: case ILCode.Brtrue: case ILCode.Beq: case ILCode.Bge: case ILCode.Bge_Un: case ILCode.Bgt: case ILCode.Bgt_Un: case ILCode.Ble: case ILCode.Ble_Un: case ILCode.Blt: case ILCode.Blt_Un: case ILCode.Bne_Un: case ILCode.BrLogicAnd: case ILCode.BrLogicOr: return new Ast.IfElseStatement() { Condition = MakeBranchCondition(byteCode), TrueStatement = new BlockStatement() { new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name) } }; } List<Ast.Expression> args = TransformExpressionArguments(byteCode); 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((Code)opCode) { #region Arithmetic case Code.Add: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); case Code.Add_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); case Code.Add_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); case Code.Div: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2); case Code.Div_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2); case Code.Mul: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2); case Code.Mul_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2); case Code.Mul_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2); case Code.Rem: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2); case Code.Rem_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2); case Code.Sub: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2); case Code.Sub_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2); case Code.Sub_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2); case Code.And: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.BitwiseAnd, arg2); case Code.Or: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.BitwiseOr, arg2); case Code.Xor: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ExclusiveOr, arg2); case Code.Shl: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftLeft, arg2); case Code.Shr: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2); case Code.Shr_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2); case Code.Neg: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Minus, arg1); case Code.Not: return new Ast.UnaryOperatorExpression(UnaryOperatorType.BitNot, arg1); #endregion #region Arrays case Code.Newarr: case (Code)ILCode.InitArray: { 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 (opCode == ILCode.InitArray) { ace.Initializer = new ArrayInitializerExpression(); ace.Initializer.Elements.AddRange(args); } else { ace.Arguments.Add(arg1); } return ace; } case Code.Ldlen: return arg1.Member("Length"); case Code.Ldelem_I: case Code.Ldelem_I1: case Code.Ldelem_I2: case Code.Ldelem_I4: case Code.Ldelem_I8: case Code.Ldelem_U1: case Code.Ldelem_U2: case Code.Ldelem_U4: case Code.Ldelem_R4: case Code.Ldelem_R8: case Code.Ldelem_Ref: return arg1.Indexer(arg2); case Code.Ldelem_Any: return InlineAssembly(byteCode, args); case Code.Ldelema: return MakeRef(arg1.Indexer(arg2)); case Code.Stelem_I: case Code.Stelem_I1: case Code.Stelem_I2: case Code.Stelem_I4: case Code.Stelem_I8: case Code.Stelem_R4: case Code.Stelem_R8: case Code.Stelem_Ref: case Code.Stelem_Any: return new Ast.AssignmentExpression(arg1.Indexer(arg2), arg3); #endregion #region Comparison case Code.Ceq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2); case Code.Cgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); case Code.Cgt_Un: // can also mean Inequality, when used with object references { TypeReference arg1Type = byteCode.Arguments[0].InferredType; if (arg1Type != null && !arg1Type.IsValueType) return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2); else return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); } case Code.Clt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); case Code.Clt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); #endregion #region Conversions case Code.Conv_I1: case Code.Conv_I2: case Code.Conv_I4: case Code.Conv_I8: case Code.Conv_U1: case Code.Conv_U2: case Code.Conv_U4: case Code.Conv_U8: return arg1; // conversion is handled by Convert() function using the info from type analysis case Code.Conv_I: return arg1.CastTo(typeof(IntPtr)); // TODO case Code.Conv_U: return arg1.CastTo(typeof(UIntPtr)); // TODO case Code.Conv_R4: return arg1.CastTo(typeof(float)); case Code.Conv_R8: return arg1.CastTo(typeof(double)); case Code.Conv_R_Un: return arg1.CastTo(typeof(double)); // TODO case Code.Conv_Ovf_I1: case Code.Conv_Ovf_I2: case Code.Conv_Ovf_I4: case Code.Conv_Ovf_I8: case Code.Conv_Ovf_U1: case Code.Conv_Ovf_U2: case Code.Conv_Ovf_U4: case Code.Conv_Ovf_U8: case Code.Conv_Ovf_I1_Un: case Code.Conv_Ovf_I2_Un: case Code.Conv_Ovf_I4_Un: case Code.Conv_Ovf_I8_Un: case Code.Conv_Ovf_U1_Un: case Code.Conv_Ovf_U2_Un: case Code.Conv_Ovf_U4_Un: case Code.Conv_Ovf_U8_Un: return arg1; // conversion was handled by Convert() function using the info from type analysis case Code.Conv_Ovf_I: return arg1.CastTo(typeof(IntPtr)); // TODO case Code.Conv_Ovf_U: return arg1.CastTo(typeof(UIntPtr)); case Code.Conv_Ovf_I_Un: return arg1.CastTo(typeof(IntPtr)); case Code.Conv_Ovf_U_Un: return arg1.CastTo(typeof(UIntPtr)); case Code.Castclass: case Code.Unbox_Any: return arg1.CastTo(operandAsTypeRef); case Code.Isinst: return arg1.CastAs(operandAsTypeRef); case Code.Box: return arg1; case Code.Unbox: return InlineAssembly(byteCode, args); #endregion #region Indirect case Code.Ldind_I: case Code.Ldind_I1: case Code.Ldind_I2: case Code.Ldind_I4: case Code.Ldind_I8: case Code.Ldind_U1: case Code.Ldind_U2: case Code.Ldind_U4: case Code.Ldind_R4: case Code.Ldind_R8: case Code.Ldind_Ref: case Code.Ldobj: if (args[0] is DirectionExpression) return ((DirectionExpression)args[0]).Expression.Detach(); else return InlineAssembly(byteCode, args); case Code.Stind_I: case Code.Stind_I1: case Code.Stind_I2: case Code.Stind_I4: case Code.Stind_I8: case Code.Stind_R4: case Code.Stind_R8: case Code.Stind_Ref: case Code.Stobj: if (args[0] is DirectionExpression) return new AssignmentExpression(((DirectionExpression)args[0]).Expression.Detach(), args[1]); else return InlineAssembly(byteCode, args); #endregion case Code.Arglist: return InlineAssembly(byteCode, args); case Code.Break: return InlineAssembly(byteCode, args); case Code.Call: return TransformCall(false, operand, methodDef, args); case Code.Callvirt: return TransformCall(true, operand, methodDef, args); case Code.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 Code.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 Code.Calli: return InlineAssembly(byteCode, args); case Code.Ckfinite: return InlineAssembly(byteCode, args); case Code.Constrained: return InlineAssembly(byteCode, args); case Code.Cpblk: return InlineAssembly(byteCode, args); case Code.Cpobj: return InlineAssembly(byteCode, args); case Code.Dup: return arg1; case Code.Endfilter: return InlineAssembly(byteCode, args); case Code.Endfinally: return null; case Code.Initblk: return InlineAssembly(byteCode, args); case Code.Initobj: if (args[0] is DirectionExpression) return new AssignmentExpression(((DirectionExpression)args[0]).Expression.Detach(), new DefaultValueExpression { Type = operandAsTypeRef }); else return InlineAssembly(byteCode, args); case Code.Jmp: return InlineAssembly(byteCode, args); case Code.Ldarg: if (methodDef.HasThis && ((ParameterDefinition)operand).Index < 0) { if (context.CurrentMethod.DeclaringType.IsValueType) return MakeRef(new Ast.ThisReferenceExpression()); else return new Ast.ThisReferenceExpression(); } else { var expr = new Ast.IdentifierExpression(((ParameterDefinition)operand).Name).WithAnnotation(operand); if (((ParameterDefinition)operand).ParameterType is ByReferenceType) return MakeRef(expr); else return expr; } case Code.Ldarga: if (methodDef.HasThis && ((ParameterDefinition)operand).Index < 0) { return MakeRef(new Ast.ThisReferenceExpression()); } else { return MakeRef(new Ast.IdentifierExpression(((ParameterDefinition)operand).Name).WithAnnotation(operand)); } case Code.Ldc_I4: return MakePrimitive((int)operand, byteCode.InferredType); case Code.Ldc_I8: case Code.Ldc_R4: case Code.Ldc_R8: return new Ast.PrimitiveExpression(operand); case Code.Ldfld: if (arg1 is DirectionExpression) arg1 = ((DirectionExpression)arg1).Expression.Detach(); return arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand); case Code.Ldsfld: return AstBuilder.ConvertType(((FieldReference)operand).DeclaringType) .Member(((FieldReference)operand).Name).WithAnnotation(operand); case Code.Stfld: if (arg1 is DirectionExpression) arg1 = ((DirectionExpression)arg1).Expression.Detach(); return new AssignmentExpression(arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand), arg2); case Code.Stsfld: return new AssignmentExpression( AstBuilder.ConvertType(((FieldReference)operand).DeclaringType) .Member(((FieldReference)operand).Name).WithAnnotation(operand), arg1); case Code.Ldflda: return MakeRef(arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand)); case Code.Ldsflda: return MakeRef( AstBuilder.ConvertType(((FieldReference)operand).DeclaringType) .Member(((FieldReference)operand).Name).WithAnnotation(operand)); case Code.Ldloc: localVariablesToDefine.Add((ILVariable)operand); return new Ast.IdentifierExpression(((ILVariable)operand).Name).WithAnnotation(operand); case Code.Ldloca: localVariablesToDefine.Add((ILVariable)operand); return MakeRef(new Ast.IdentifierExpression(((ILVariable)operand).Name).WithAnnotation(operand)); case Code.Ldnull: return new Ast.NullReferenceExpression(); case Code.Ldstr: return new Ast.PrimitiveExpression(operand); case Code.Ldtoken: if (operand is Cecil.TypeReference) { return new Ast.TypeOfExpression { Type = operandAsTypeRef }.Member("TypeHandle"); } else { return InlineAssembly(byteCode, args); } case Code.Leave: return null; case Code.Localloc: return InlineAssembly(byteCode, args); case Code.Mkrefany: return InlineAssembly(byteCode, args); case Code.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; } } var oce = new Ast.ObjectCreateExpression(); oce.Type = AstBuilder.ConvertType(declaringType); oce.Arguments.AddRange(args); return oce.WithAnnotation(operand); } case Code.No: return InlineAssembly(byteCode, args); case Code.Nop: return null; case Code.Pop: return arg1; case Code.Readonly: return InlineAssembly(byteCode, args); case Code.Refanytype: return InlineAssembly(byteCode, args); case Code.Refanyval: return InlineAssembly(byteCode, args); case Code.Ret: { if (methodDef.ReturnType.FullName != "System.Void") { return new Ast.ReturnStatement { Expression = arg1 }; } else { return new Ast.ReturnStatement(); } } case Code.Rethrow: return new Ast.ThrowStatement(); case Code.Sizeof: return new Ast.SizeOfExpression { Type = operandAsTypeRef }; case Code.Starg: return new Ast.AssignmentExpression(new Ast.IdentifierExpression(((ParameterDefinition)operand).Name).WithAnnotation(operand), arg1); case Code.Stloc: { ILVariable locVar = (ILVariable)operand; localVariablesToDefine.Add(locVar); return new Ast.AssignmentExpression(new Ast.IdentifierExpression(locVar.Name).WithAnnotation(locVar), arg1); } case Code.Switch: return InlineAssembly(byteCode, args); case Code.Tail: return InlineAssembly(byteCode, args); case Code.Throw: return new Ast.ThrowStatement { Expression = arg1 }; case Code.Unaligned: return InlineAssembly(byteCode, args); case Code.Volatile: return InlineAssembly(byteCode, args); default: throw new Exception("Unknown OpCode: " + opCode); } }
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); } }
AstNode TransformByteCode(ILExpression byteCode, List<Ast.Expression> args) { ILCode opCode = byteCode.Code; object operand = byteCode.Operand; AstType operandAsTypeRef = AstBuilder.ConvertType(operand as Cecil.TypeReference); ILExpression operandAsByteCode = operand as ILExpression; 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; BlockStatement branchCommand = null; if (byteCode.Operand is ILLabel) { branchCommand = new BlockStatement(); branchCommand.Add(new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name)); } switch((Code)opCode) { #region Arithmetic case Code.Add: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); case Code.Add_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); case Code.Add_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); case Code.Div: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2); case Code.Div_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2); case Code.Mul: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2); case Code.Mul_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2); case Code.Mul_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2); case Code.Rem: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2); case Code.Rem_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2); case Code.Sub: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2); case Code.Sub_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2); case Code.Sub_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2); case Code.And: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.BitwiseAnd, arg2); case Code.Or: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.BitwiseOr, arg2); case Code.Xor: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ExclusiveOr, arg2); case Code.Shl: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftLeft, arg2); case Code.Shr: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2); case Code.Shr_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2); case Code.Neg: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Minus, arg1); case Code.Not: return new Ast.UnaryOperatorExpression(UnaryOperatorType.BitNot, arg1); #endregion #region Arrays case Code.Newarr: { var ace = new Ast.ArrayCreateExpression(); ace.Type = operandAsTypeRef; ace.Arguments.Add(arg1); return ace; } case Code.Ldlen: return arg1.Member("Length"); case Code.Ldelem_I: case Code.Ldelem_I1: case Code.Ldelem_I2: case Code.Ldelem_I4: case Code.Ldelem_I8: case Code.Ldelem_U1: case Code.Ldelem_U2: case Code.Ldelem_U4: case Code.Ldelem_R4: case Code.Ldelem_R8: case Code.Ldelem_Ref: return arg1.Indexer(arg2); case Code.Ldelem_Any: return InlineAssembly(byteCode, args); case Code.Ldelema: return MakeRef(arg1.Indexer(arg2)); case Code.Stelem_I: case Code.Stelem_I1: case Code.Stelem_I2: case Code.Stelem_I4: case Code.Stelem_I8: case Code.Stelem_R4: case Code.Stelem_R8: case Code.Stelem_Ref: return new Ast.AssignmentExpression(arg1.Indexer(arg2), arg3); case Code.Stelem_Any: return InlineAssembly(byteCode, args); #endregion #region Branching case Code.Br: return new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name); case Code.Brfalse: return new Ast.IfElseStatement(new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1), branchCommand); case Code.Brtrue: return new Ast.IfElseStatement(arg1, branchCommand); case Code.Beq: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2), branchCommand); case Code.Bge: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2), branchCommand); case Code.Bge_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2), branchCommand); case Code.Bgt: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2), branchCommand); case Code.Bgt_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2), branchCommand); case Code.Ble: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2), branchCommand); case Code.Ble_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2), branchCommand); case Code.Blt: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2), branchCommand); case Code.Blt_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2), branchCommand); case Code.Bne_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2), branchCommand); #endregion #region Comparison case Code.Ceq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2); case Code.Cgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); case Code.Cgt_Un: // can also mean Inequality, when used with object references { TypeReference arg1Type = byteCode.Arguments[0].InferredType; if (arg1Type != null && !arg1Type.IsValueType) return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2); else return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); } case Code.Clt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); case Code.Clt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); #endregion #region Conversions case Code.Conv_I1: case Code.Conv_I2: case Code.Conv_I4: case Code.Conv_I8: case Code.Conv_U1: case Code.Conv_U2: case Code.Conv_U4: case Code.Conv_U8: return arg1; // conversion is handled by Convert() function using the info from type analysis case Code.Conv_I: return arg1.CastTo(typeof(IntPtr)); // TODO case Code.Conv_U: return arg1.CastTo(typeof(UIntPtr)); // TODO case Code.Conv_R4: return arg1.CastTo(typeof(float)); case Code.Conv_R8: return arg1.CastTo(typeof(double)); case Code.Conv_R_Un: return arg1.CastTo(typeof(double)); // TODO case Code.Conv_Ovf_I1: case Code.Conv_Ovf_I2: case Code.Conv_Ovf_I4: case Code.Conv_Ovf_I8: case Code.Conv_Ovf_U1: case Code.Conv_Ovf_U2: case Code.Conv_Ovf_U4: case Code.Conv_Ovf_U8: case Code.Conv_Ovf_I1_Un: case Code.Conv_Ovf_I2_Un: case Code.Conv_Ovf_I4_Un: case Code.Conv_Ovf_I8_Un: case Code.Conv_Ovf_U1_Un: case Code.Conv_Ovf_U2_Un: case Code.Conv_Ovf_U4_Un: case Code.Conv_Ovf_U8_Un: return arg1; // conversion was handled by Convert() function using the info from type analysis case Code.Conv_Ovf_I: return arg1.CastTo(typeof(IntPtr)); // TODO case Code.Conv_Ovf_U: return arg1.CastTo(typeof(UIntPtr)); case Code.Conv_Ovf_I_Un: return arg1.CastTo(typeof(IntPtr)); case Code.Conv_Ovf_U_Un: return arg1.CastTo(typeof(UIntPtr)); case Code.Castclass: case Code.Unbox_Any: return arg1.CastTo(operandAsTypeRef); case Code.Isinst: return arg1.CastAs(operandAsTypeRef); case Code.Box: return arg1; case Code.Unbox: return InlineAssembly(byteCode, args); #endregion #region Indirect case Code.Ldind_I: return InlineAssembly(byteCode, args); case Code.Ldind_I1: return InlineAssembly(byteCode, args); case Code.Ldind_I2: return InlineAssembly(byteCode, args); case Code.Ldind_I4: return InlineAssembly(byteCode, args); case Code.Ldind_I8: return InlineAssembly(byteCode, args); case Code.Ldind_U1: return InlineAssembly(byteCode, args); case Code.Ldind_U2: return InlineAssembly(byteCode, args); case Code.Ldind_U4: return InlineAssembly(byteCode, args); case Code.Ldind_R4: return InlineAssembly(byteCode, args); case Code.Ldind_R8: return InlineAssembly(byteCode, args); case Code.Ldind_Ref: return InlineAssembly(byteCode, args); case Code.Stind_I: return InlineAssembly(byteCode, args); case Code.Stind_I1: return InlineAssembly(byteCode, args); case Code.Stind_I2: return InlineAssembly(byteCode, args); case Code.Stind_I4: return InlineAssembly(byteCode, args); case Code.Stind_I8: return InlineAssembly(byteCode, args); case Code.Stind_R4: return InlineAssembly(byteCode, args); case Code.Stind_R8: return InlineAssembly(byteCode, args); case Code.Stind_Ref: return InlineAssembly(byteCode, args); #endregion case Code.Arglist: return InlineAssembly(byteCode, args); case Code.Break: return InlineAssembly(byteCode, args); case Code.Call: return TransformCall(false, operand, methodDef, args); case Code.Callvirt: return TransformCall(true, operand, methodDef, args); case Code.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 Code.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 Code.Calli: return InlineAssembly(byteCode, args); case Code.Ckfinite: return InlineAssembly(byteCode, args); case Code.Constrained: return InlineAssembly(byteCode, args); case Code.Cpblk: return InlineAssembly(byteCode, args); case Code.Cpobj: return InlineAssembly(byteCode, args); case Code.Dup: return arg1; case Code.Endfilter: return InlineAssembly(byteCode, args); case Code.Endfinally: return null; case Code.Initblk: return InlineAssembly(byteCode, args); case Code.Initobj: return InlineAssembly(byteCode, args); case Code.Jmp: return InlineAssembly(byteCode, args); case Code.Ldarg: if (methodDef.HasThis && ((ParameterDefinition)operand).Index < 0) { return new Ast.ThisReferenceExpression(); } else { return new Ast.IdentifierExpression(((ParameterDefinition)operand).Name).WithAnnotation(operand); } case Code.Ldarga: if (methodDef.HasThis && ((ParameterDefinition)operand).Index < 0) { return MakeRef(new Ast.ThisReferenceExpression()); } else { return MakeRef(new Ast.IdentifierExpression(((ParameterDefinition)operand).Name).WithAnnotation(operand)); } case Code.Ldc_I4: return PrimitiveExpression((int)operand, byteCode.InferredType); case Code.Ldc_I8: case Code.Ldc_R4: case Code.Ldc_R8: return new Ast.PrimitiveExpression(operand); case Code.Ldfld: return arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand); case Code.Ldsfld: return AstBuilder.ConvertType(((FieldReference)operand).DeclaringType) .Member(((FieldReference)operand).Name).WithAnnotation(operand); case Code.Stfld: return new AssignmentExpression(arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand), arg2); case Code.Stsfld: return new AssignmentExpression( AstBuilder.ConvertType(((FieldReference)operand).DeclaringType) .Member(((FieldReference)operand).Name).WithAnnotation(operand), arg1); case Code.Ldflda: return MakeRef(arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand)); case Code.Ldsflda: return MakeRef( AstBuilder.ConvertType(((FieldReference)operand).DeclaringType) .Member(((FieldReference)operand).Name).WithAnnotation(operand)); case Code.Ldloc: return new Ast.IdentifierExpression(((ILVariable)operand).Name).WithAnnotation(operand); case Code.Ldloca: return MakeRef(new Ast.IdentifierExpression(((ILVariable)operand).Name).WithAnnotation(operand)); case Code.Ldnull: return new Ast.NullReferenceExpression(); case Code.Ldobj: return InlineAssembly(byteCode, args); case Code.Ldstr: return new Ast.PrimitiveExpression(operand); case Code.Ldtoken: if (operand is Cecil.TypeReference) { return new Ast.TypeOfExpression { Type = operandAsTypeRef }.Member("TypeHandle"); } else { return InlineAssembly(byteCode, args); } case Code.Leave: return null; case Code.Localloc: return InlineAssembly(byteCode, args); case Code.Mkrefany: return InlineAssembly(byteCode, args); case Code.Newobj: { Cecil.TypeReference declaringType = ((MethodReference)operand).DeclaringType; // TODO: Ensure that the corrent overloaded constructor is called /*if (declaringType is ArrayType) { shouldn't this be newarr? return new Ast.ArrayCreateExpression { Type = AstBuilder.ConvertType((ArrayType)declaringType), Arguments = args }; }*/ var oce = new Ast.ObjectCreateExpression(); oce.Type = AstBuilder.ConvertType(declaringType); oce.Arguments.AddRange(args); return oce.WithAnnotation(operand); } case Code.No: return InlineAssembly(byteCode, args); case Code.Nop: return null; case Code.Pop: return arg1; case Code.Readonly: return InlineAssembly(byteCode, args); case Code.Refanytype: return InlineAssembly(byteCode, args); case Code.Refanyval: return InlineAssembly(byteCode, args); case Code.Ret: { if (methodDef.ReturnType.FullName != "System.Void") { return new Ast.ReturnStatement { Expression = arg1 }; } else { return new Ast.ReturnStatement(); } } case Code.Rethrow: return new Ast.ThrowStatement(); case Code.Sizeof: return new Ast.SizeOfExpression { Type = AstBuilder.ConvertType(operand as TypeReference) }; case Code.Starg: return new Ast.AssignmentExpression(new Ast.IdentifierExpression(((ParameterDefinition)operand).Name).WithAnnotation(operand), arg1); case Code.Stloc: { ILVariable locVar = (ILVariable)operand; if (!localVariablesToDefine.Contains(locVar)) { localVariablesToDefine.Add(locVar); } return new Ast.AssignmentExpression(new Ast.IdentifierExpression(locVar.Name).WithAnnotation(locVar), arg1); } case Code.Stobj: return InlineAssembly(byteCode, args); case Code.Switch: return InlineAssembly(byteCode, args); case Code.Tail: return InlineAssembly(byteCode, args); case Code.Throw: return new Ast.ThrowStatement { Expression = arg1 }; case Code.Unaligned: return InlineAssembly(byteCode, args); case Code.Volatile: return InlineAssembly(byteCode, args); default: throw new Exception("Unknown OpCode: " + opCode); } }