mirror of https://github.com/icsharpcode/ILSpy.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
598 lines
30 KiB
598 lines
30 KiB
using System; |
|
using System.Collections.Generic; |
|
|
|
using Ast = ICSharpCode.NRefactory.Ast; |
|
using ICSharpCode.NRefactory.Ast; |
|
|
|
using Cecil = Mono.Cecil; |
|
using Mono.Cecil; |
|
using Mono.Cecil.Cil; |
|
|
|
using Decompiler.ControlFlow; |
|
|
|
namespace Decompiler |
|
{ |
|
public class AstMetodBodyBuilder |
|
{ |
|
MethodDefinition methodDef; |
|
static Dictionary<string, Cecil.TypeReference> localVarTypes = new Dictionary<string, Cecil.TypeReference>(); |
|
static Dictionary<string, bool> localVarDefined = new Dictionary<string, bool>(); |
|
|
|
public static BlockStatement CreateMetodBody(MethodDefinition methodDef) |
|
{ |
|
AstMetodBodyBuilder builder = new AstMetodBodyBuilder(); |
|
builder.methodDef = methodDef; |
|
return builder.CreateMetodBody(); |
|
} |
|
|
|
public BlockStatement CreateMetodBody() |
|
{ |
|
Ast.BlockStatement astBlock = new Ast.BlockStatement(); |
|
|
|
methodDef.Body.Simplify(); |
|
|
|
ByteCodeCollection body = new ByteCodeCollection(methodDef); |
|
StackExpressionCollection exprCollection = new StackExpressionCollection(body); |
|
try { |
|
exprCollection.Optimize(); |
|
} catch (StopOptimizations) { |
|
} |
|
|
|
MethodBodyGraph bodyGraph = new MethodBodyGraph(exprCollection); |
|
try { |
|
bodyGraph.Optimize(); |
|
} catch (StopOptimizations) { |
|
} |
|
|
|
List<string> intNames = new List<string>(new string[] {"i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t"}); |
|
|
|
foreach(VariableDefinition varDef in methodDef.Body.Variables) { |
|
if (varDef.VariableType.FullName == Cecil.Constants.Int32 && |
|
varDef.Name.StartsWith("V_") && |
|
intNames.Count > 0) |
|
{ |
|
varDef.Name = intNames[0]; |
|
intNames.RemoveAt(0); |
|
} |
|
localVarTypes[varDef.Name] = varDef.VariableType; |
|
localVarDefined[varDef.Name] = false; |
|
|
|
// Ast.VariableDeclaration astVar = new Ast.VariableDeclaration(varDef.Name); |
|
// Ast.LocalVariableDeclaration astLocalVar = new Ast.LocalVariableDeclaration(astVar); |
|
// astLocalVar.TypeReference = new Ast.TypeReference(varDef.VariableType.FullName); |
|
// astBlock.Children.Add(astLocalVar); |
|
} |
|
|
|
astBlock.Children.AddRange(TransformNodes(bodyGraph.Childs)); |
|
|
|
return astBlock; |
|
} |
|
|
|
IEnumerable<Ast.INode> TransformNodes(IEnumerable<Node> nodes) |
|
{ |
|
foreach(Node node in nodes) { |
|
foreach(Ast.Statement stmt in TransformNode(node)) { |
|
yield return stmt; |
|
} |
|
} |
|
} |
|
|
|
IEnumerable<Ast.INode> TransformNode(Node node) |
|
{ |
|
if (Options.NodeComments) { |
|
yield return MakeComment("// " + node.Description); |
|
} |
|
|
|
yield return new Ast.LabelStatement(node.Label); |
|
|
|
if (node is BasicBlock) { |
|
foreach(StackExpression expr in ((BasicBlock)node).Body) { |
|
yield return TransformExpressionToStatement(expr); |
|
} |
|
Node fallThroughNode = ((BasicBlock)node).FallThroughBasicBlock; |
|
// If there is default branch and it is not the following node |
|
if (fallThroughNode != null) { |
|
yield return new Ast.GotoStatement(fallThroughNode.Label); |
|
} |
|
} else if (node is AcyclicGraph) { |
|
Ast.BlockStatement blockStatement = new Ast.BlockStatement(); |
|
blockStatement.Children.AddRange(TransformNodes(node.Childs)); |
|
yield return blockStatement; |
|
} else if (node is Loop) { |
|
Ast.BlockStatement blockStatement = new Ast.BlockStatement(); |
|
blockStatement.Children.AddRange(TransformNodes(node.Childs)); |
|
yield return new Ast.ForStatement( |
|
null, |
|
null, |
|
null, |
|
blockStatement |
|
); |
|
} else if (node is Block) { |
|
foreach(Ast.INode inode in TransformNodes(node.Childs)) { |
|
yield return inode; |
|
} |
|
} else if (node is Branch) { |
|
yield return new Ast.LabelStatement(((Branch)node).FirstBasicBlock.Label); |
|
|
|
Ast.BlockStatement trueBlock = new Ast.BlockStatement(); |
|
trueBlock.Children.Add(new Ast.GotoStatement(((Branch)node).TrueSuccessor.Label)); |
|
|
|
Ast.BlockStatement falseBlock = new Ast.BlockStatement(); |
|
falseBlock.Children.Add(new Ast.GotoStatement(((Branch)node).FalseSuccessor.Label)); |
|
|
|
Ast.IfElseStatement ifElseStmt = new Ast.IfElseStatement( |
|
MakeBranchCondition((Branch)node), |
|
trueBlock, |
|
falseBlock |
|
); |
|
trueBlock.Parent = ifElseStmt; |
|
falseBlock.Parent = ifElseStmt; |
|
|
|
yield return ifElseStmt; |
|
} else if (node is ConditionalNode) { |
|
ConditionalNode conditionalNode = (ConditionalNode)node; |
|
yield return new Ast.LabelStatement(conditionalNode.Condition.FirstBasicBlock.Label); |
|
|
|
Ast.BlockStatement trueBlock = new Ast.BlockStatement(); |
|
// The block entry code |
|
trueBlock.Children.Add(new Ast.GotoStatement(conditionalNode.Condition.TrueSuccessor.Label)); |
|
// Sugested content |
|
trueBlock.Children.AddRange(TransformNode(conditionalNode.TrueBody)); |
|
|
|
Ast.BlockStatement falseBlock = new Ast.BlockStatement(); |
|
// The block entry code |
|
falseBlock.Children.Add(new Ast.GotoStatement(conditionalNode.Condition.FalseSuccessor.Label)); |
|
// Sugested content |
|
falseBlock.Children.AddRange(TransformNode(conditionalNode.FalseBody)); |
|
|
|
Ast.IfElseStatement ifElseStmt = new Ast.IfElseStatement( |
|
// Method bodies are swapped |
|
new Ast.UnaryOperatorExpression( |
|
new Ast.ParenthesizedExpression( |
|
MakeBranchCondition(conditionalNode.Condition) |
|
), |
|
UnaryOperatorType.Not |
|
), |
|
falseBlock, |
|
trueBlock |
|
); |
|
trueBlock.Parent = ifElseStmt; |
|
falseBlock.Parent = ifElseStmt; |
|
|
|
yield return ifElseStmt; |
|
} else { |
|
throw new Exception("Bad node type"); |
|
} |
|
|
|
if (Options.NodeComments) { |
|
yield return MakeComment(""); |
|
} |
|
} |
|
|
|
List<Ast.Expression> TransformExpressionArguments(StackExpression expr) |
|
{ |
|
List<Ast.Expression> args = new List<Ast.Expression>(); |
|
foreach(CilStackSlot stackSlot in expr.StackBefore.PeekCount(expr.PopCount)) { |
|
string name = string.Format("expr{0:X2}", stackSlot.AllocadedBy.Offset); |
|
args.Add(new Ast.IdentifierExpression(name)); |
|
} |
|
// Args generated by nested expressions (which must be closed) |
|
foreach(StackExpression nestedExpr in expr.LastArguments) { |
|
args.Add((Ast.Expression)TransformExpression(nestedExpr)); |
|
} |
|
return args; |
|
} |
|
|
|
object TransformExpression(StackExpression expr) |
|
{ |
|
List<Ast.Expression> args = TransformExpressionArguments(expr); |
|
return TransformByteCode(methodDef, expr.LastByteCode, args); |
|
} |
|
|
|
Ast.Statement TransformExpressionToStatement(StackExpression expr) |
|
{ |
|
object codeExpr = TransformExpression(expr); |
|
if (codeExpr is Ast.Expression) { |
|
if (expr.PushCount == 1) { |
|
string type = expr.LastByteCode.Type.FullName; |
|
string name = string.Format("expr{0:X2}", expr.LastByteCode.Offset); |
|
Ast.LocalVariableDeclaration astLocal = new Ast.LocalVariableDeclaration(new Ast.TypeReference(type.ToString())); |
|
astLocal.Variables.Add(new Ast.VariableDeclaration(name, (Ast.Expression)codeExpr)); |
|
return astLocal; |
|
} else { |
|
return new Ast.ExpressionStatement((Ast.Expression)codeExpr); |
|
} |
|
} else if (codeExpr is Ast.Statement) { |
|
return (Ast.Statement)codeExpr; |
|
} else { |
|
throw new Exception(); |
|
} |
|
} |
|
|
|
static Ast.ExpressionStatement MakeComment(string text) |
|
{ |
|
text = "/***" + text + "***/"; |
|
return new Ast.ExpressionStatement(new PrimitiveExpression(text, text)); |
|
} |
|
|
|
Ast.Expression MakeBranchCondition(Branch branch) |
|
{ |
|
return new ParenthesizedExpression(MakeBranchCondition_Internal(branch)); |
|
} |
|
|
|
Ast.Expression MakeBranchCondition_Internal(Branch branch) |
|
{ |
|
if (branch is SimpleBranch) { |
|
List<Ast.Expression> args = TransformExpressionArguments(((SimpleBranch)branch).BasicBlock.Body[0]); |
|
Ast.Expression arg1 = args.Count >= 1 ? args[0] : null; |
|
Ast.Expression arg2 = args.Count >= 2 ? args[1] : null; |
|
switch(((SimpleBranch)branch).BasicBlock.Body[0].LastByteCode.OpCode.Code) { |
|
case Code.Brfalse: return new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.Not); |
|
case Code.Brtrue: return arg1; |
|
case Code.Beq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2); |
|
case Code.Bge: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2); |
|
case Code.Bge_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2); |
|
case Code.Bgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); |
|
case Code.Bgt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); |
|
case Code.Ble: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2); |
|
case Code.Ble_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2); |
|
case Code.Blt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); |
|
case Code.Blt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); |
|
case Code.Bne_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2); |
|
default: throw new Exception("Bad opcode"); |
|
} |
|
} else if (branch is ShortCircuitBranch) { |
|
ShortCircuitBranch scBranch = (ShortCircuitBranch)branch; |
|
switch(scBranch.Operator) { |
|
case ShortCircuitOperator.LeftAndRight: |
|
return new BinaryOperatorExpression( |
|
MakeBranchCondition(scBranch.Left), |
|
BinaryOperatorType.LogicalAnd, |
|
MakeBranchCondition(scBranch.Right) |
|
); |
|
case ShortCircuitOperator.LeftOrRight: |
|
return new BinaryOperatorExpression( |
|
MakeBranchCondition(scBranch.Left), |
|
BinaryOperatorType.LogicalOr, |
|
MakeBranchCondition(scBranch.Right) |
|
); |
|
case ShortCircuitOperator.NotLeftAndRight: |
|
return new BinaryOperatorExpression( |
|
new UnaryOperatorExpression(MakeBranchCondition(scBranch.Left), UnaryOperatorType.Not), |
|
BinaryOperatorType.LogicalAnd, |
|
MakeBranchCondition(scBranch.Right) |
|
); |
|
case ShortCircuitOperator.NotLeftOrRight: |
|
return new BinaryOperatorExpression( |
|
new UnaryOperatorExpression(MakeBranchCondition(scBranch.Left), UnaryOperatorType.Not), |
|
BinaryOperatorType.LogicalOr, |
|
MakeBranchCondition(scBranch.Right) |
|
); |
|
default: |
|
throw new Exception("Bad operator"); |
|
} |
|
} else { |
|
throw new Exception("Bad type"); |
|
} |
|
} |
|
|
|
static object TransformByteCode(MethodDefinition methodDef, ByteCode byteCode, List<Ast.Expression> args) |
|
{ |
|
try { |
|
object ret = TransformByteCode_Internal(methodDef, byteCode, args); |
|
if (ret is Ast.Expression) { |
|
ret = new ParenthesizedExpression((Ast.Expression)ret); |
|
} |
|
return ret; |
|
} catch (NotImplementedException) { |
|
// Output the operand of the unknown IL code as well |
|
if (byteCode.Operand != null) { |
|
args.Insert(0, new IdentifierExpression(byteCode.FormatedOperand)); |
|
} |
|
return new Ast.InvocationExpression(new IdentifierExpression("IL__" + byteCode.OpCode.Name), args); |
|
} |
|
} |
|
|
|
static object TransformByteCode_Internal(MethodDefinition methodDef, ByteCode byteCode, List<Ast.Expression> args) |
|
{ |
|
OpCode opCode = byteCode.OpCode; |
|
object operand = byteCode.Operand; |
|
Ast.TypeReference operandAsTypeRef = operand is Cecil.TypeReference ? new Ast.TypeReference(((Cecil.TypeReference)operand).FullName) : null; |
|
ByteCode operandAsByteCode = operand as 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; |
|
|
|
Ast.Statement branchCommand = null; |
|
if (operand is ByteCode) { |
|
branchCommand = new Ast.GotoStatement(((ByteCode)operand).Expression.BasicBlock.Label); |
|
} |
|
|
|
switch(opCode.Code) { |
|
#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.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(arg1, UnaryOperatorType.Minus); |
|
case Code.Not: return new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.BitNot); |
|
#endregion |
|
#region Arrays |
|
case Code.Newarr: |
|
operandAsTypeRef.RankSpecifier = new int[] {0}; |
|
return new Ast.ArrayCreateExpression(operandAsTypeRef, new List<Expression>(new Expression[] {arg1})); |
|
|
|
case Code.Ldlen: return new Ast.MemberReferenceExpression(arg1, "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 new Ast.IndexerExpression(arg1, new List<Expression>(new Expression[] {arg2})); |
|
case Code.Ldelem_Any: throw new NotImplementedException(); |
|
case Code.Ldelema: return new Ast.IndexerExpression(arg1, new List<Expression>(new Expression[] {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(new Ast.IndexerExpression(arg1, new List<Expression>(new Expression[] {arg2})), AssignmentOperatorType.Assign, arg3); |
|
case Code.Stelem_Any: throw new NotImplementedException(); |
|
#endregion |
|
#region Branching |
|
case Code.Br: return branchCommand; |
|
case Code.Brfalse: return new Ast.IfElseStatement(new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.Not), 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, ConvertIntToBool(arg2)); |
|
case Code.Cgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); |
|
case Code.Cgt_Un: 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_I: return new Ast.CastExpression(new Ast.TypeReference(typeof(int).FullName), arg1, CastType.Cast); // TODO |
|
case Code.Conv_I1: return new Ast.CastExpression(new Ast.TypeReference(typeof(SByte).FullName), arg1, CastType.Cast); |
|
case Code.Conv_I2: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int16).FullName), arg1, CastType.Cast); |
|
case Code.Conv_I4: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int32).FullName), arg1, CastType.Cast); |
|
case Code.Conv_I8: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int64).FullName), arg1, CastType.Cast); |
|
case Code.Conv_U: return new Ast.CastExpression(new Ast.TypeReference(typeof(uint).FullName), arg1, CastType.Cast); // TODO |
|
case Code.Conv_U1: return new Ast.CastExpression(new Ast.TypeReference(typeof(Byte).FullName), arg1, CastType.Cast); |
|
case Code.Conv_U2: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt16).FullName), arg1, CastType.Cast); |
|
case Code.Conv_U4: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt32).FullName), arg1, CastType.Cast); |
|
case Code.Conv_U8: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt64).FullName), arg1, CastType.Cast); |
|
case Code.Conv_R4: return new Ast.CastExpression(new Ast.TypeReference(typeof(float).FullName), arg1, CastType.Cast); |
|
case Code.Conv_R8: return new Ast.CastExpression(new Ast.TypeReference(typeof(double).FullName), arg1, CastType.Cast); |
|
case Code.Conv_R_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(double).FullName), arg1, CastType.Cast); // TODO |
|
|
|
case Code.Conv_Ovf_I: return new Ast.CastExpression(new Ast.TypeReference(typeof(int).FullName), arg1, CastType.Cast); // TODO |
|
case Code.Conv_Ovf_I1: return new Ast.CastExpression(new Ast.TypeReference(typeof(SByte).FullName), arg1, CastType.Cast); |
|
case Code.Conv_Ovf_I2: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int16).FullName), arg1, CastType.Cast); |
|
case Code.Conv_Ovf_I4: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int32).FullName), arg1, CastType.Cast); |
|
case Code.Conv_Ovf_I8: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int64).FullName), arg1, CastType.Cast); |
|
case Code.Conv_Ovf_U: return new Ast.CastExpression(new Ast.TypeReference(typeof(uint).FullName), arg1, CastType.Cast); // TODO |
|
case Code.Conv_Ovf_U1: return new Ast.CastExpression(new Ast.TypeReference(typeof(Byte).FullName), arg1, CastType.Cast); |
|
case Code.Conv_Ovf_U2: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt16).FullName), arg1, CastType.Cast); |
|
case Code.Conv_Ovf_U4: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt32).FullName), arg1, CastType.Cast); |
|
case Code.Conv_Ovf_U8: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt64).FullName), arg1, CastType.Cast); |
|
|
|
case Code.Conv_Ovf_I_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(int).FullName), arg1, CastType.Cast); // TODO |
|
case Code.Conv_Ovf_I1_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(SByte).FullName), arg1, CastType.Cast); |
|
case Code.Conv_Ovf_I2_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int16).FullName), arg1, CastType.Cast); |
|
case Code.Conv_Ovf_I4_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int32).FullName), arg1, CastType.Cast); |
|
case Code.Conv_Ovf_I8_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int64).FullName), arg1, CastType.Cast); |
|
case Code.Conv_Ovf_U_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(uint).FullName), arg1, CastType.Cast); // TODO |
|
case Code.Conv_Ovf_U1_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(Byte).FullName), arg1, CastType.Cast); |
|
case Code.Conv_Ovf_U2_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt16).FullName), arg1, CastType.Cast); |
|
case Code.Conv_Ovf_U4_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt32).FullName), arg1, CastType.Cast); |
|
case Code.Conv_Ovf_U8_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt64).FullName), arg1, CastType.Cast); |
|
#endregion |
|
#region Indirect |
|
case Code.Ldind_I: throw new NotImplementedException(); |
|
case Code.Ldind_I1: throw new NotImplementedException(); |
|
case Code.Ldind_I2: throw new NotImplementedException(); |
|
case Code.Ldind_I4: throw new NotImplementedException(); |
|
case Code.Ldind_I8: throw new NotImplementedException(); |
|
case Code.Ldind_U1: throw new NotImplementedException(); |
|
case Code.Ldind_U2: throw new NotImplementedException(); |
|
case Code.Ldind_U4: throw new NotImplementedException(); |
|
case Code.Ldind_R4: throw new NotImplementedException(); |
|
case Code.Ldind_R8: throw new NotImplementedException(); |
|
case Code.Ldind_Ref: throw new NotImplementedException(); |
|
|
|
case Code.Stind_I: throw new NotImplementedException(); |
|
case Code.Stind_I1: throw new NotImplementedException(); |
|
case Code.Stind_I2: throw new NotImplementedException(); |
|
case Code.Stind_I4: throw new NotImplementedException(); |
|
case Code.Stind_I8: throw new NotImplementedException(); |
|
case Code.Stind_R4: throw new NotImplementedException(); |
|
case Code.Stind_R8: throw new NotImplementedException(); |
|
case Code.Stind_Ref: throw new NotImplementedException(); |
|
#endregion |
|
case Code.Arglist: throw new NotImplementedException(); |
|
case Code.Box: throw new NotImplementedException(); |
|
case Code.Break: throw new NotImplementedException(); |
|
case Code.Call: |
|
case Code.Callvirt: |
|
// TODO: Diferentiate vitual and non-vitual dispach |
|
Cecil.MethodReference cecilMethod = ((MethodReference)operand); |
|
Ast.Expression target; |
|
List<Ast.Expression> methodArgs = new List<Ast.Expression>(args); |
|
if (cecilMethod.HasThis) { |
|
target = methodArgs[0]; |
|
methodArgs.RemoveAt(0); |
|
} else { |
|
target = new Ast.IdentifierExpression(cecilMethod.DeclaringType.FullName); |
|
} |
|
// TODO: Hack, detect properties properly |
|
if (cecilMethod.Name.StartsWith("get_")) { |
|
return new Ast.MemberReferenceExpression(target, cecilMethod.Name.Remove(0, 4)); |
|
} else if (cecilMethod.Name.StartsWith("set_")) { |
|
return new Ast.AssignmentExpression( |
|
new Ast.MemberReferenceExpression(target, cecilMethod.Name.Remove(0, 4)), |
|
AssignmentOperatorType.Assign, |
|
methodArgs[0] |
|
); |
|
} else { |
|
return new Ast.InvocationExpression( |
|
new Ast.MemberReferenceExpression(target, cecilMethod.Name), |
|
methodArgs |
|
); |
|
} |
|
case Code.Calli: throw new NotImplementedException(); |
|
case Code.Castclass: return new Ast.CastExpression(operandAsTypeRef, arg1, CastType.Cast); |
|
case Code.Ckfinite: throw new NotImplementedException(); |
|
case Code.Constrained: throw new NotImplementedException(); |
|
case Code.Cpblk: throw new NotImplementedException(); |
|
case Code.Cpobj: throw new NotImplementedException(); |
|
case Code.Dup: throw new NotImplementedException(); |
|
case Code.Endfilter: throw new NotImplementedException(); |
|
case Code.Endfinally: throw new NotImplementedException(); |
|
case Code.Initblk: throw new NotImplementedException(); |
|
case Code.Initobj: throw new NotImplementedException(); |
|
case Code.Isinst: throw new NotImplementedException(); |
|
case Code.Jmp: throw new NotImplementedException(); |
|
case Code.Ldarg: |
|
if (methodDef.HasThis && ((ParameterDefinition)operand).Sequence == 0) { |
|
return new Ast.ThisReferenceExpression(); |
|
} else { |
|
return new Ast.IdentifierExpression(((ParameterDefinition)operand).Name); |
|
} |
|
case Code.Ldarga: throw new NotImplementedException(); |
|
case Code.Ldc_I4: |
|
case Code.Ldc_I8: |
|
case Code.Ldc_R4: |
|
case Code.Ldc_R8: return new Ast.PrimitiveExpression(operand, null); |
|
case Code.Ldfld: { |
|
FieldDefinition field = (FieldDefinition) operand; |
|
if (field.IsStatic) { |
|
return new Ast.MemberReferenceExpression( |
|
new Ast.IdentifierExpression(field.DeclaringType.FullName), |
|
field.Name |
|
); |
|
} else { |
|
return new Ast.MemberReferenceExpression(arg1, field.Name); |
|
} |
|
} |
|
case Code.Stfld: { |
|
FieldDefinition field = (FieldDefinition) operand; |
|
if (field.IsStatic) { |
|
return new AssignmentExpression( |
|
new Ast.MemberReferenceExpression( |
|
new Ast.IdentifierExpression(field.DeclaringType.FullName), |
|
field.Name |
|
), |
|
AssignmentOperatorType.Assign, |
|
arg1 |
|
); |
|
} else { |
|
return new AssignmentExpression( |
|
new Ast.MemberReferenceExpression(arg1, field.Name), |
|
AssignmentOperatorType.Assign, |
|
arg2 |
|
); |
|
} |
|
} |
|
case Code.Ldflda: throw new NotImplementedException(); |
|
case Code.Ldftn: throw new NotImplementedException(); |
|
case Code.Ldloc: return new Ast.IdentifierExpression(((VariableDefinition)operand).Name); |
|
case Code.Ldloca: throw new NotImplementedException(); |
|
case Code.Ldnull: return new Ast.PrimitiveExpression(null, null); |
|
case Code.Ldobj: throw new NotImplementedException(); |
|
case Code.Ldsfld: throw new NotImplementedException(); |
|
case Code.Ldsflda: throw new NotImplementedException(); |
|
case Code.Ldstr: return new Ast.PrimitiveExpression(operand, null); |
|
case Code.Ldtoken: |
|
if (operand is Cecil.TypeReference) { |
|
return new Ast.MemberReferenceExpression( |
|
new Ast.TypeOfExpression(operandAsTypeRef), |
|
"TypeHandle" |
|
); |
|
} else { |
|
throw new NotImplementedException(); |
|
} |
|
case Code.Ldvirtftn: throw new NotImplementedException(); |
|
case Code.Leave: throw new NotImplementedException(); |
|
case Code.Localloc: throw new NotImplementedException(); |
|
case Code.Mkrefany: throw new NotImplementedException(); |
|
case Code.Newobj: |
|
// TODO: Ensure that the corrent overloaded constructor is called |
|
return new Ast.ObjectCreateExpression( |
|
new Ast.TypeReference(((MethodReference)operand).DeclaringType.FullName), |
|
new List<Expression>(args) |
|
); |
|
case Code.No: throw new NotImplementedException(); |
|
case Code.Nop: return new Ast.PrimitiveExpression("/* No-op */", "/* No-op */"); |
|
case Code.Or: throw new NotImplementedException(); |
|
case Code.Pop: throw new NotImplementedException(); |
|
case Code.Readonly: throw new NotImplementedException(); |
|
case Code.Refanytype: throw new NotImplementedException(); |
|
case Code.Refanyval: throw new NotImplementedException(); |
|
case Code.Ret: return new Ast.ReturnStatement(methodDef.ReturnType.ReturnType.FullName != Cecil.Constants.Void ? arg1 : null); |
|
case Code.Rethrow: throw new NotImplementedException(); |
|
case Code.Sizeof: throw new NotImplementedException(); |
|
case Code.Starg: throw new NotImplementedException(); |
|
case Code.Stloc: |
|
string name = ((VariableDefinition)operand).Name; |
|
if (localVarDefined[name]) { |
|
return new Ast.AssignmentExpression(new Ast.IdentifierExpression(name), AssignmentOperatorType.Assign, arg1); |
|
} else { |
|
Ast.LocalVariableDeclaration astLocalVar = new Ast.LocalVariableDeclaration(new Ast.VariableDeclaration(name, arg1)); |
|
astLocalVar.TypeReference = new Ast.TypeReference(localVarTypes[name].FullName); |
|
localVarDefined[name] = true; |
|
return astLocalVar; |
|
} |
|
case Code.Stobj: throw new NotImplementedException(); |
|
case Code.Stsfld: throw new NotImplementedException(); |
|
case Code.Switch: throw new NotImplementedException(); |
|
case Code.Tail: throw new NotImplementedException(); |
|
case Code.Throw: throw new NotImplementedException(); |
|
case Code.Unaligned: throw new NotImplementedException(); |
|
case Code.Unbox: throw new NotImplementedException(); |
|
case Code.Unbox_Any: throw new NotImplementedException(); |
|
case Code.Volatile: throw new NotImplementedException(); |
|
default: throw new Exception("Unknown OpCode: " + opCode); |
|
} |
|
} |
|
|
|
static Ast.Expression ConvertIntToBool(Ast.Expression astInt) |
|
{ |
|
return new Ast.ParenthesizedExpression(new Ast.BinaryOperatorExpression(astInt, BinaryOperatorType.InEquality, new Ast.PrimitiveExpression(0, "0"))); |
|
} |
|
} |
|
}
|
|
|