Browse Source

Add support for more dynamic binary operators.

pull/1165/head
Siegfried Pammer 8 years ago
parent
commit
c4f41f459f
  1. 101
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 11
      ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs
  3. 47
      ICSharpCode.Decompiler/IL/Instructions/DynamicInstructions.cs
  4. 2
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
  5. 2
      ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs

101
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -2341,7 +2341,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2341,7 +2341,7 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitDynamicConvertInstruction(DynamicConvertInstruction inst, TranslationContext context)
{
return Translate(inst.Argument).ConvertTo(inst.Type, this, inst.IsChecked);
return Translate(inst.Argument).ConvertTo(inst.Type, this, inst.IsChecked, allowImplicitConversion: !inst.IsExplicit);
}
protected internal override TranslatedExpression VisitDynamicGetIndexInstruction(DynamicGetIndexInstruction inst, TranslationContext context)
@ -2471,47 +2471,70 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2471,47 +2471,70 @@ namespace ICSharpCode.Decompiler.CSharp
{
switch (inst.Operation) {
case ExpressionType.Add:
return CreateBinaryOperator(BinaryOperatorType.Add);
case ExpressionType.AddAssign:
return CreateBinaryOperator(BinaryOperatorType.Add, isChecked: inst.BinderFlags.HasFlag(CSharpBinderFlags.CheckedContext));
case ExpressionType.AddChecked:
case ExpressionType.AddAssignChecked:
return CreateBinaryOperator(BinaryOperatorType.Add, isChecked: true);
case ExpressionType.Subtract:
return CreateBinaryOperator(BinaryOperatorType.Subtract);
case ExpressionType.SubtractAssign:
return CreateBinaryOperator(BinaryOperatorType.Subtract, isChecked: inst.BinderFlags.HasFlag(CSharpBinderFlags.CheckedContext));
case ExpressionType.SubtractChecked:
case ExpressionType.SubtractAssignChecked:
return CreateBinaryOperator(BinaryOperatorType.Subtract, isChecked: true);
case ExpressionType.Multiply:
return CreateBinaryOperator(BinaryOperatorType.Multiply);
case ExpressionType.MultiplyAssign:
return CreateBinaryOperator(BinaryOperatorType.Multiply, isChecked: inst.BinderFlags.HasFlag(CSharpBinderFlags.CheckedContext));
case ExpressionType.MultiplyChecked:
case ExpressionType.MultiplyAssignChecked:
return CreateBinaryOperator(BinaryOperatorType.Multiply, isChecked: true);
case ExpressionType.Divide:
return CreateBinaryOperator(BinaryOperatorType.Divide);
case ExpressionType.DivideAssign:
return CreateBinaryOperator(BinaryOperatorType.Divide, isChecked: false);
case ExpressionType.Modulo:
return CreateBinaryOperator(BinaryOperatorType.Modulus);
case ExpressionType.ModuloAssign:
return CreateBinaryOperator(BinaryOperatorType.Modulus, isChecked: false);
case ExpressionType.Equal:
return CreateBinaryOperator(BinaryOperatorType.Equality);
return CreateBinaryOperator(BinaryOperatorType.Equality, isChecked: false);
case ExpressionType.NotEqual:
return CreateBinaryOperator(BinaryOperatorType.InEquality);
return CreateBinaryOperator(BinaryOperatorType.InEquality, isChecked: false);
case ExpressionType.LessThan:
return CreateBinaryOperator(BinaryOperatorType.LessThan);
return CreateBinaryOperator(BinaryOperatorType.LessThan, isChecked: false);
case ExpressionType.LessThanOrEqual:
return CreateBinaryOperator(BinaryOperatorType.LessThanOrEqual);
return CreateBinaryOperator(BinaryOperatorType.LessThanOrEqual, isChecked: false);
case ExpressionType.GreaterThan:
return CreateBinaryOperator(BinaryOperatorType.GreaterThan);
return CreateBinaryOperator(BinaryOperatorType.GreaterThan, isChecked: false);
case ExpressionType.GreaterThanOrEqual:
return CreateBinaryOperator(BinaryOperatorType.GreaterThanOrEqual);
case ExpressionType.Or:
return CreateBinaryOperator(BinaryOperatorType.BitwiseOr);
return CreateBinaryOperator(BinaryOperatorType.GreaterThanOrEqual, isChecked: false);
case ExpressionType.And:
return CreateBinaryOperator(BinaryOperatorType.BitwiseAnd);
case ExpressionType.AndAssign:
return CreateBinaryOperator(BinaryOperatorType.BitwiseAnd, isChecked: false);
case ExpressionType.Or:
case ExpressionType.OrAssign:
return CreateBinaryOperator(BinaryOperatorType.BitwiseOr, isChecked: false);
case ExpressionType.ExclusiveOr:
return CreateBinaryOperator(BinaryOperatorType.ExclusiveOr);
case ExpressionType.ExclusiveOrAssign:
return CreateBinaryOperator(BinaryOperatorType.ExclusiveOr, isChecked: false);
case ExpressionType.LeftShift:
return CreateBinaryOperator(BinaryOperatorType.ShiftLeft);
case ExpressionType.LeftShiftAssign:
return CreateBinaryOperator(BinaryOperatorType.ShiftLeft, isChecked: false);
case ExpressionType.RightShift:
return CreateBinaryOperator(BinaryOperatorType.ShiftRight);
case ExpressionType.RightShiftAssign:
return CreateBinaryOperator(BinaryOperatorType.ShiftRight, isChecked: false);
default:
return base.VisitDynamicBinaryOperatorInstruction(inst, context);
}
TranslatedExpression CreateBinaryOperator(BinaryOperatorType operatorType)
TranslatedExpression CreateBinaryOperator(BinaryOperatorType operatorType, bool isChecked)
{
var left = TranslateDynamicArgument(inst.Left, inst.LeftArgumentInfo);
var right = TranslateDynamicArgument(inst.Right, inst.RightArgumentInfo);
return new BinaryOperatorExpression(left.Expression, operatorType, right.Expression)
.WithILInstruction(inst).WithRR(new ResolveResult(SpecialType.Dynamic));
var boe = new BinaryOperatorExpression(left.Expression, operatorType, right.Expression);
if (isChecked)
boe.AddAnnotation(AddCheckedBlocks.CheckedAnnotation);
else
boe.AddAnnotation(AddCheckedBlocks.UncheckedAnnotation);
return boe.WithILInstruction(inst).WithRR(new ResolveResult(SpecialType.Dynamic));
}
}
@ -2519,15 +2542,17 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2519,15 +2542,17 @@ namespace ICSharpCode.Decompiler.CSharp
{
switch (inst.Operation) {
case ExpressionType.Not:
return CreateUnaryOperator(UnaryOperatorType.Not);
return CreateUnaryOperator(UnaryOperatorType.Not, isChecked: false);
case ExpressionType.Decrement:
return CreateUnaryOperator(UnaryOperatorType.Decrement);
return CreateUnaryOperator(UnaryOperatorType.Decrement, isChecked: false);
case ExpressionType.Increment:
return CreateUnaryOperator(UnaryOperatorType.Increment);
return CreateUnaryOperator(UnaryOperatorType.Increment, isChecked: false);
case ExpressionType.Negate:
return CreateUnaryOperator(UnaryOperatorType.Minus);
return CreateUnaryOperator(UnaryOperatorType.Minus, isChecked: inst.BinderFlags.HasFlag(CSharpBinderFlags.CheckedContext));
case ExpressionType.NegateChecked:
return CreateUnaryOperator(UnaryOperatorType.Minus, isChecked: true);
case ExpressionType.UnaryPlus:
return CreateUnaryOperator(UnaryOperatorType.Plus);
return CreateUnaryOperator(UnaryOperatorType.Plus, isChecked: inst.BinderFlags.HasFlag(CSharpBinderFlags.CheckedContext));
case ExpressionType.IsTrue:
var operand = TranslateDynamicArgument(inst.Operand, inst.OperandArgumentInfo);
Expression expr;
@ -2540,15 +2565,25 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2540,15 +2565,25 @@ namespace ICSharpCode.Decompiler.CSharp
}
return expr.WithILInstruction(inst)
.WithRR(new ResolveResult(compilation.FindType(KnownTypeCode.Boolean)));
case ExpressionType.IsFalse:
operand = TranslateDynamicArgument(inst.Operand, inst.OperandArgumentInfo);
// Create a dummy conditional to ensure "operator false" will be invoked.
expr = new ConditionalExpression(operand, new PrimitiveExpression(false), new PrimitiveExpression(true));
return expr.WithILInstruction(inst)
.WithRR(new ResolveResult(compilation.FindType(KnownTypeCode.Boolean)));
default:
return base.VisitDynamicUnaryOperatorInstruction(inst, context);
}
TranslatedExpression CreateUnaryOperator(UnaryOperatorType operatorType)
TranslatedExpression CreateUnaryOperator(UnaryOperatorType operatorType, bool isChecked)
{
var operand = TranslateDynamicArgument(inst.Operand, inst.OperandArgumentInfo);
return new UnaryOperatorExpression(operatorType, operand.Expression)
.WithILInstruction(inst).WithRR(new ResolveResult(SpecialType.Dynamic));
var uoe = new UnaryOperatorExpression(operatorType, operand.Expression);
if (isChecked)
uoe.AddAnnotation(AddCheckedBlocks.CheckedAnnotation);
else
uoe.AddAnnotation(AddCheckedBlocks.UncheckedAnnotation);
return uoe.WithILInstruction(inst).WithRR(new ResolveResult(SpecialType.Dynamic));
}
}
@ -2557,8 +2592,12 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2557,8 +2592,12 @@ namespace ICSharpCode.Decompiler.CSharp
var target = TranslateDynamicArgument(inst.Target, inst.TargetArgumentInfo);
var value = TranslateDynamicArgument(inst.Value, inst.ValueArgumentInfo);
return new AssignmentExpression(target, AssignmentExpression.GetAssignmentOperatorTypeFromExpressionType(inst.Operation), value)
.WithILInstruction(inst)
var ae = new AssignmentExpression(target, AssignmentExpression.GetAssignmentOperatorTypeFromExpressionType(inst.Operation), value);
if (inst.BinderFlags.HasFlag(CSharpBinderFlags.CheckedContext))
ae.AddAnnotation(AddCheckedBlocks.CheckedAnnotation);
else
ae.AddAnnotation(AddCheckedBlocks.UncheckedAnnotation);
return ae.WithILInstruction(inst)
.WithRR(new OperatorResolveResult(SpecialType.Dynamic, inst.Operation, new[] { target.ResolveResult, value.ResolveResult }));
}

11
ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs

@ -233,12 +233,14 @@ namespace ICSharpCode.Decompiler.IL @@ -233,12 +233,14 @@ namespace ICSharpCode.Decompiler.IL
public ExpressionType Operation { get; }
public CSharpArgumentInfo TargetArgumentInfo { get; }
public CSharpArgumentInfo ValueArgumentInfo { get; }
public CSharpBinderFlags BinderFlags { get; }
public DynamicCompoundAssign(ExpressionType op, ILInstruction target, CSharpArgumentInfo targetArgumentInfo, ILInstruction value, CSharpArgumentInfo valueArgumentInfo)
public DynamicCompoundAssign(ExpressionType op, CSharpBinderFlags binderFlags, ILInstruction target, CSharpArgumentInfo targetArgumentInfo, ILInstruction value, CSharpArgumentInfo valueArgumentInfo)
: base(OpCode.DynamicCompoundAssign, CompoundAssignmentTypeFromOperation(op), target, value)
{
if (!IsExpressionTypeSupported(op))
throw new ArgumentOutOfRangeException("op");
this.BinderFlags = binderFlags;
this.Operation = op;
this.TargetArgumentInfo = targetArgumentInfo;
this.ValueArgumentInfo = valueArgumentInfo;
@ -249,16 +251,13 @@ namespace ICSharpCode.Decompiler.IL @@ -249,16 +251,13 @@ namespace ICSharpCode.Decompiler.IL
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write("." + Operation.ToString().ToLower());
DynamicInstruction.WriteBinderFlags(BinderFlags, output, options);
if (CompoundAssignmentType == CompoundAssignmentType.EvaluatesToNewValue)
output.Write(".new");
else
output.Write(".old");
output.Write(' ');
output.Write('(');
this.Target.WriteTo(output, options);
output.Write(", ");
this.Value.WriteTo(output, options);
output.Write(')');
DynamicInstruction.WriteArgumentList(output, options, (Target, TargetArgumentInfo), (Value, ValueArgumentInfo));
}
internal static bool IsExpressionTypeSupported(ExpressionType type)

47
ICSharpCode.Decompiler/IL/Instructions/DynamicInstructions.cs

@ -73,34 +73,39 @@ namespace ICSharpCode.Decompiler.IL @@ -73,34 +73,39 @@ namespace ICSharpCode.Decompiler.IL
protected void WriteBinderFlags(ITextOutput output, ILAstWritingOptions options)
{
if ((BinderFlags & CSharpBinderFlags.BinaryOperationLogical) != 0)
WriteBinderFlags(BinderFlags, output, options);
}
internal static void WriteBinderFlags(CSharpBinderFlags flags, ITextOutput output, ILAstWritingOptions options)
{
if ((flags & CSharpBinderFlags.BinaryOperationLogical) != 0)
output.Write(".logic");
if ((BinderFlags & CSharpBinderFlags.CheckedContext) != 0)
if ((flags & CSharpBinderFlags.CheckedContext) != 0)
output.Write(".checked");
if ((BinderFlags & CSharpBinderFlags.ConvertArrayIndex) != 0)
if ((flags & CSharpBinderFlags.ConvertArrayIndex) != 0)
output.Write(".arrayindex");
if ((BinderFlags & CSharpBinderFlags.ConvertExplicit) != 0)
if ((flags & CSharpBinderFlags.ConvertExplicit) != 0)
output.Write(".explicit");
if ((BinderFlags & CSharpBinderFlags.InvokeSimpleName) != 0)
if ((flags & CSharpBinderFlags.InvokeSimpleName) != 0)
output.Write(".invokesimple");
if ((BinderFlags & CSharpBinderFlags.InvokeSpecialName) != 0)
if ((flags & CSharpBinderFlags.InvokeSpecialName) != 0)
output.Write(".invokespecial");
if ((BinderFlags & CSharpBinderFlags.ResultDiscarded) != 0)
if ((flags & CSharpBinderFlags.ResultDiscarded) != 0)
output.Write(".discard");
if ((BinderFlags & CSharpBinderFlags.ResultIndexed) != 0)
if ((flags & CSharpBinderFlags.ResultIndexed) != 0)
output.Write(".resultindexed");
if ((BinderFlags & CSharpBinderFlags.ValueFromCompoundAssignment) != 0)
if ((flags & CSharpBinderFlags.ValueFromCompoundAssignment) != 0)
output.Write(".compound");
}
public abstract CSharpArgumentInfo GetArgumentInfoOfChild(int index);
protected void WriteArgumentList(ITextOutput output, ILAstWritingOptions options, params (ILInstruction, CSharpArgumentInfo)[] arguments)
internal static void WriteArgumentList(ITextOutput output, ILAstWritingOptions options, params (ILInstruction, CSharpArgumentInfo)[] arguments)
{
WriteArgumentList(output, options, (IEnumerable<(ILInstruction, CSharpArgumentInfo)>)arguments);
}
protected void WriteArgumentList(ITextOutput output, ILAstWritingOptions options, IEnumerable<(ILInstruction, CSharpArgumentInfo)> arguments)
internal static void WriteArgumentList(ITextOutput output, ILAstWritingOptions options, IEnumerable<(ILInstruction, CSharpArgumentInfo)> arguments)
{
output.Write('(');
int j = 0;
@ -147,6 +152,8 @@ namespace ICSharpCode.Decompiler.IL @@ -147,6 +152,8 @@ namespace ICSharpCode.Decompiler.IL
public bool IsChecked => (BinderFlags & CSharpBinderFlags.CheckedContext) != 0;
public bool IsExplicit => (BinderFlags & CSharpBinderFlags.ConvertExplicit) != 0;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
return default(CSharpArgumentInfo);
@ -190,7 +197,7 @@ namespace ICSharpCode.Decompiler.IL @@ -190,7 +197,7 @@ namespace ICSharpCode.Decompiler.IL
WriteArgumentList(output, options, Arguments.Zip(ArgumentInfo));
}
public override StackType ResultType => SpecialType.Dynamic.GetStackType();
public override StackType ResultType => StackType.O;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
@ -223,7 +230,7 @@ namespace ICSharpCode.Decompiler.IL @@ -223,7 +230,7 @@ namespace ICSharpCode.Decompiler.IL
WriteArgumentList(output, options, (Target, TargetArgumentInfo));
}
public override StackType ResultType => SpecialType.Dynamic.GetStackType();
public override StackType ResultType => StackType.O;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
@ -259,7 +266,7 @@ namespace ICSharpCode.Decompiler.IL @@ -259,7 +266,7 @@ namespace ICSharpCode.Decompiler.IL
WriteArgumentList(output, options, (Target, TargetArgumentInfo), (Value, ValueArgumentInfo));
}
public override StackType ResultType => SpecialType.Dynamic.GetStackType();
public override StackType ResultType => StackType.O;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
@ -296,7 +303,7 @@ namespace ICSharpCode.Decompiler.IL @@ -296,7 +303,7 @@ namespace ICSharpCode.Decompiler.IL
WriteArgumentList(output, options, Arguments.Zip(ArgumentInfo));
}
public override StackType ResultType => SpecialType.Dynamic.GetStackType();
public override StackType ResultType => StackType.O;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
@ -328,7 +335,7 @@ namespace ICSharpCode.Decompiler.IL @@ -328,7 +335,7 @@ namespace ICSharpCode.Decompiler.IL
WriteArgumentList(output, options, Arguments.Zip(ArgumentInfo));
}
public override StackType ResultType => SpecialType.Dynamic.GetStackType();
public override StackType ResultType => StackType.O;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
@ -360,7 +367,7 @@ namespace ICSharpCode.Decompiler.IL @@ -360,7 +367,7 @@ namespace ICSharpCode.Decompiler.IL
WriteArgumentList(output, options, Arguments.Zip(ArgumentInfo));
}
public override StackType ResultType => SpecialType.Dynamic.GetStackType();
public override StackType ResultType => StackType.O;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
@ -396,7 +403,7 @@ namespace ICSharpCode.Decompiler.IL @@ -396,7 +403,7 @@ namespace ICSharpCode.Decompiler.IL
WriteArgumentList(output, options, (Left, LeftArgumentInfo), (Right, RightArgumentInfo));
}
public override StackType ResultType => SpecialType.Dynamic.GetStackType();
public override StackType ResultType => StackType.O;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{
@ -441,7 +448,7 @@ namespace ICSharpCode.Decompiler.IL @@ -441,7 +448,7 @@ namespace ICSharpCode.Decompiler.IL
case ExpressionType.IsTrue:
return StackType.I4; // bool
default:
return SpecialType.Dynamic.GetStackType();
return StackType.O;
}
}
}
@ -478,7 +485,7 @@ namespace ICSharpCode.Decompiler.IL @@ -478,7 +485,7 @@ namespace ICSharpCode.Decompiler.IL
WriteArgumentList(output, options, Arguments.Zip(ArgumentInfo));
}
public override StackType ResultType => SpecialType.Dynamic.GetStackType();
public override StackType ResultType => StackType.O;
public override CSharpArgumentInfo GetArgumentInfoOfChild(int index)
{

2
ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

@ -419,7 +419,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -419,7 +419,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return;
}
context.Step("dynamic.setmember.compound -> dynamic.compound.op", inst);
inst.ReplaceWith(new DynamicCompoundAssign(binaryOp.Operation, binaryOp.Left, binaryOp.LeftArgumentInfo, binaryOp.Right, binaryOp.RightArgumentInfo));
inst.ReplaceWith(new DynamicCompoundAssign(binaryOp.Operation, binaryOp.BinderFlags, binaryOp.Left, binaryOp.LeftArgumentInfo, binaryOp.Right, binaryOp.RightArgumentInfo));
}
IfInstruction HandleConditionalOperator(IfInstruction inst)

2
ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs

@ -297,7 +297,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -297,7 +297,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!IsMatchingCompoundLoad(dynamicBinaryOp.Left, compoundStore, forbiddenVariable: storeInSetter?.Variable))
return false;
context.Step($"Compound assignment (dynamic binary)", compoundStore);
newInst = new DynamicCompoundAssign(dynamicBinaryOp.Operation, dynamicBinaryOp.Left, dynamicBinaryOp.LeftArgumentInfo, dynamicBinaryOp.Right, dynamicBinaryOp.RightArgumentInfo);
newInst = new DynamicCompoundAssign(dynamicBinaryOp.Operation, dynamicBinaryOp.BinderFlags, dynamicBinaryOp.Left, dynamicBinaryOp.LeftArgumentInfo, dynamicBinaryOp.Right, dynamicBinaryOp.RightArgumentInfo);
} else {
return false;
}

Loading…
Cancel
Save