Browse Source

Add support for syntax sugar when writing out the ILAst.

pull/870/head
Daniel Grunwald 8 years ago
parent
commit
53a050552b
  1. 3
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/LiftedOperators.cs
  2. 4
      ICSharpCode.Decompiler/IL/Instructions.cs
  3. 15
      ICSharpCode.Decompiler/IL/Instructions.tt
  4. 6
      ICSharpCode.Decompiler/IL/Instructions/Comp.cs
  5. 9
      ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
  6. 18
      ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs
  7. 49
      ICSharpCode.Decompiler/IL/Instructions/MemoryInstructions.cs
  8. 21
      ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs
  9. 26
      ILSpy/Languages/ILAstLanguage.cs

3
ICSharpCode.Decompiler.Tests/TestCases/Pretty/LiftedOperators.cs

@ -134,8 +134,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -134,8 +134,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
a |= x();
a ^= x();
Console.WriteLine(x() & a);
Console.WriteLine(x() | a);
Console.WriteLine(x() ^ a);
(new bool?[0])[0] ^= x();
(new bool?[0])[0] ^= a;
}
public static void BoolValueConst(bool? a)

4
ICSharpCode.Decompiler/IL/Instructions.cs

@ -2946,7 +2946,7 @@ namespace ICSharpCode.Decompiler.IL @@ -2946,7 +2946,7 @@ namespace ICSharpCode.Decompiler.IL
return InstructionFlags.SideEffect | InstructionFlags.MayThrow;
}
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
void OriginalWriteTo(ITextOutput output, ILAstWritingOptions options)
{
if (IsVolatile)
output.Write("volatile.");
@ -3070,7 +3070,7 @@ namespace ICSharpCode.Decompiler.IL @@ -3070,7 +3070,7 @@ namespace ICSharpCode.Decompiler.IL
return InstructionFlags.SideEffect | InstructionFlags.MayThrow;
}
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
void OriginalWriteTo(ITextOutput output, ILAstWritingOptions options)
{
if (IsVolatile)
output.Write("volatile.");

15
ICSharpCode.Decompiler/IL/Instructions.tt

@ -172,16 +172,16 @@ @@ -172,16 +172,16 @@
CustomClassName("LdFlda"), CustomArguments("target"), MayThrowIfNotDelayed, HasFieldOperand, ResultType("Ref")),
new OpCode("ldsflda", "Load static field address",
CustomClassName("LdsFlda"), NoArguments, ResultType("Ref"), HasFieldOperand),
new OpCode("castclass", "Casts an object to a class.",
CustomClassName("CastClass"), Unary, HasTypeOperand, MayThrow, ResultType("type.GetStackType()")),
new OpCode("isinst", "Test if object is instance of class or interface.",
CustomClassName("IsInst"), Unary, HasTypeOperand, ResultType("O")),
new OpCode("ldobj", "Indirect load (ref/pointer dereference).",
CustomClassName("LdObj"), CustomArguments("target"), HasTypeOperand, MemoryAccess,
CustomClassName("LdObj"), CustomArguments("target"), HasTypeOperand, MemoryAccess, CustomWriteToButKeepOriginal,
SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow, ResultType("type.GetStackType()")),
new OpCode("stobj", "Indirect store (store to ref/pointer).",
CustomClassName("StObj"), CustomArguments("target", "value"), HasTypeOperand, MemoryAccess,
CustomClassName("StObj"), CustomArguments("target", "value"), HasTypeOperand, MemoryAccess, CustomWriteToButKeepOriginal,
SupportsVolatilePrefix, SupportsUnalignedPrefix, MayThrow, ResultType("type.GetStackType()")),
new OpCode("box", "Boxes a value.",
@ -277,7 +277,11 @@ namespace <#=opCode.Namespace#> @@ -277,7 +277,11 @@ namespace <#=opCode.Namespace#>
}
<# } #>
<# if (opCode.GenerateWriteTo) { #>
<# if (opCode.CustomWriteToButKeepOriginal) { #>
void OriginalWriteTo(ITextOutput output, ILAstWritingOptions options)
<# } else { #>
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
<# } #>
{<#=Body(opCode.WriteToBody)#>}
<# } #>
<# if (opCode.GenerateAcceptVisitor) { #>
@ -462,6 +466,7 @@ namespace ICSharpCode.Decompiler.IL @@ -462,6 +466,7 @@ namespace ICSharpCode.Decompiler.IL
public bool GenerateWriteTo = false;
public bool CustomWriteToButKeepOriginal = false;
public List<string> WriteOpCodePrefix = new List<string>();
public List<string> WriteOpCodeSuffix = new List<string>();
public List<string> WriteOperand = new List<string>();
@ -512,6 +517,10 @@ namespace ICSharpCode.Decompiler.IL @@ -512,6 +517,10 @@ namespace ICSharpCode.Decompiler.IL
static Action<OpCode> CustomWriteTo = opCode => {
opCode.GenerateWriteTo = false;
};
static Action<OpCode> CustomWriteToButKeepOriginal = opCode => {
opCode.CustomWriteToButKeepOriginal = true;
};
static Action<OpCode> CustomComputeFlags = opCode => {
opCode.GenerateComputeFlags = false;

6
ICSharpCode.Decompiler/IL/Instructions/Comp.cs

@ -175,6 +175,12 @@ namespace ICSharpCode.Decompiler.IL @@ -175,6 +175,12 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
if (options.UseLogicOperationSugar && MatchLogicNot(out var arg)) {
output.Write("logic.not(");
arg.WriteTo(output, options);
output.Write(')');
return;
}
output.Write(OpCode);
switch (Sign) {
case Sign.Signed:

9
ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs

@ -743,5 +743,14 @@ namespace ICSharpCode.Decompiler.IL @@ -743,5 +743,14 @@ namespace ICSharpCode.Decompiler.IL
public class ILAstWritingOptions
{
/// <summary>
/// Sugar for logic.not/and/or.
/// </summary>
public bool UseLogicOperationSugar { get; set; }
/// <summary>
/// Sugar for ldfld/stfld.
/// </summary>
public bool UseFieldSugar { get; set; }
}
}

18
ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs

@ -78,6 +78,24 @@ namespace ICSharpCode.Decompiler.IL @@ -78,6 +78,24 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
if (options.UseLogicOperationSugar) {
if (MatchLogicAnd(out var lhs, out var rhs)) {
output.Write("logic.and(");
lhs.WriteTo(output, options);
output.Write(", ");
rhs.WriteTo(output, options);
output.Write(')');
return;
}
if (MatchLogicOr(out lhs, out rhs)) {
output.Write("logic.or(");
lhs.WriteTo(output, options);
output.Write(", ");
rhs.WriteTo(output, options);
output.Write(')');
return;
}
}
output.Write(OpCode);
output.Write(" (");
condition.WriteTo(output, options);

49
ICSharpCode.Decompiler/IL/Instructions/MemoryInstructions.cs

@ -34,4 +34,53 @@ namespace ICSharpCode.Decompiler.IL @@ -34,4 +34,53 @@ namespace ICSharpCode.Decompiler.IL
/// </summary>
bool IsVolatile { get; set; }
}
partial class LdObj
{
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
if (options.UseFieldSugar) {
if (this.MatchLdFld(out var target, out var field)) {
output.Write("ldfld ");
Disassembler.DisassemblerHelpers.WriteOperand(output, field);
output.Write('(');
this.target.WriteTo(output, options);
output.Write(')');
return;
} else if (this.MatchLdsFld(out field)) {
output.Write("ldsfld ");
Disassembler.DisassemblerHelpers.WriteOperand(output, field);
return;
}
}
OriginalWriteTo(output, options);
}
}
partial class StObj
{
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
if (options.UseFieldSugar) {
if (this.MatchStFld(out var target, out var field, out var value)) {
output.Write("stfld ");
Disassembler.DisassemblerHelpers.WriteOperand(output, field);
output.Write('(');
this.target.WriteTo(output, options);
output.Write(", ");
this.value.WriteTo(output, options);
output.Write(')');
return;
} else if (this.MatchStsFld(out field, out value)) {
output.Write("stsfld ");
Disassembler.DisassemblerHelpers.WriteOperand(output, field);
output.Write('(');
this.value.WriteTo(output, options);
output.Write(')');
return;
}
}
OriginalWriteTo(output, options);
}
}
}

21
ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs

@ -324,17 +324,9 @@ namespace ICSharpCode.Decompiler.IL @@ -324,17 +324,9 @@ namespace ICSharpCode.Decompiler.IL
}
}
public bool MatchLdsFld(IField field)
{
if (this is LdObj ldobj && ldobj.Target is LdsFlda ldsflda) {
return field.Equals(ldsflda.Field);
}
return false;
}
public bool MatchLdFld(out ILInstruction target, out IField field)
{
if (this is LdObj ldobj && ldobj.Target is LdFlda ldflda) {
if (this is LdObj ldobj && ldobj.Target is LdFlda ldflda && ldobj.UnalignedPrefix == 0 && !ldobj.IsVolatile) {
target = ldflda.Target;
field = ldflda.Field;
return true;
@ -346,7 +338,7 @@ namespace ICSharpCode.Decompiler.IL @@ -346,7 +338,7 @@ namespace ICSharpCode.Decompiler.IL
public bool MatchLdsFld(out IField field)
{
if (this is LdObj ldobj && ldobj.Target is LdsFlda ldsflda) {
if (this is LdObj ldobj && ldobj.Target is LdsFlda ldsflda && ldobj.UnalignedPrefix == 0 && !ldobj.IsVolatile) {
field = ldsflda.Field;
return true;
}
@ -354,9 +346,14 @@ namespace ICSharpCode.Decompiler.IL @@ -354,9 +346,14 @@ namespace ICSharpCode.Decompiler.IL
return false;
}
public bool MatchLdsFld(IField field)
{
return MatchLdsFld(out var f) && f.Equals(field);
}
public bool MatchStsFld(out IField field, out ILInstruction value)
{
if (this is StObj stobj && stobj.Target is LdsFlda ldsflda) {
if (this is StObj stobj && stobj.Target is LdsFlda ldsflda && stobj.UnalignedPrefix == 0 && !stobj.IsVolatile) {
field = ldsflda.Field;
value = stobj.Value;
return true;
@ -368,7 +365,7 @@ namespace ICSharpCode.Decompiler.IL @@ -368,7 +365,7 @@ namespace ICSharpCode.Decompiler.IL
public bool MatchStFld(out ILInstruction target, out IField field, out ILInstruction value)
{
if (this is StObj stobj && stobj.Target is LdFlda ldflda) {
if (this is StObj stobj && stobj.Target is LdFlda ldflda && stobj.UnalignedPrefix == 0 && !stobj.IsVolatile) {
target = ldflda.Target;
field = ldflda.Field;
value = stobj.Value;

26
ILSpy/Languages/ILAstLanguage.cs

@ -141,12 +141,16 @@ namespace ICSharpCode.ILSpy @@ -141,12 +141,16 @@ namespace ICSharpCode.ILSpy
class BlockIL : ILAstLanguage
{
readonly IReadOnlyList<IILTransform> transforms;
readonly ILAstWritingOptions writingOptions = new ILAstWritingOptions {
UseFieldSugar = true,
UseLogicOperationSugar = true
};
public BlockIL(IReadOnlyList<IILTransform> transforms) : base("ILAst")
{
this.transforms = transforms;
}
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{
base.DecompileMethod(method, output, options);
@ -173,11 +177,27 @@ namespace ICSharpCode.ILSpy @@ -173,11 +177,27 @@ namespace ICSharpCode.ILSpy
OnStepperUpdated(new EventArgs());
}
}
(output as ISmartTextOutput)?.AddUIElement(OptionsCheckBox(nameof(writingOptions.UseFieldSugar)));
output.WriteLine();
(output as ISmartTextOutput)?.AddUIElement(OptionsCheckBox(nameof(writingOptions.UseLogicOperationSugar)));
output.WriteLine();
(output as ISmartTextOutput)?.AddButton(Images.ViewCode, "Show Steps", delegate {
DebugSteps.Show();
});
output.WriteLine();
il.WriteTo(output);
il.WriteTo(output, writingOptions);
}
Func<System.Windows.UIElement> OptionsCheckBox(string propertyName)
{
return () => {
var checkBox = new System.Windows.Controls.CheckBox();
checkBox.Content = propertyName;
checkBox.Cursor = System.Windows.Input.Cursors.Arrow;
checkBox.SetBinding(System.Windows.Controls.CheckBox.IsCheckedProperty,
new System.Windows.Data.Binding(propertyName) { Source = writingOptions });
return checkBox;
};
}
}
}

Loading…
Cancel
Save