コード例 #1
0
        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);
            }
        }
コード例 #2
0
        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);
            }
        }
コード例 #3
0
ファイル: AstMethodBodyBuilder.cs プロジェクト: petr-k/ILSpy
        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);
            }
        }