diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
index 387d453b5..dd2bd4a91 100644
--- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
+++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
@@ -271,6 +271,8 @@
+
+
diff --git a/ICSharpCode.Decompiler/IL/Instructions.cs b/ICSharpCode.Decompiler/IL/Instructions.cs
index 015b312b7..c6f361279 100644
--- a/ICSharpCode.Decompiler/IL/Instructions.cs
+++ b/ICSharpCode.Decompiler/IL/Instructions.cs
@@ -158,6 +158,8 @@ namespace ICSharpCode.Decompiler.IL
/// Converts an array pointer (O) to a reference to the first element, or to a null reference if the array is null or empty.
/// Also used to convert a string to a reference to the first character.
ArrayToPointer,
+ /// Maps a string value to an integer. This is used in switch(string).
+ StringToInt,
/// Push a typed reference of type class onto the stack.
MakeRefAny,
/// Push the type token stored in a typed reference.
@@ -4021,6 +4023,87 @@ namespace ICSharpCode.Decompiler.IL
}
}
namespace ICSharpCode.Decompiler.IL
+{
+ /// Maps a string value to an integer. This is used in switch(string).
+ public sealed partial class StringToInt : ILInstruction
+ {
+ public static readonly SlotInfo ArgumentSlot = new SlotInfo("Argument", canInlineInto: true);
+ ILInstruction argument;
+ public ILInstruction Argument {
+ get { return this.argument; }
+ set {
+ ValidateChild(value);
+ SetChildInstruction(ref this.argument, value, 0);
+ }
+ }
+ protected sealed override int GetChildCount()
+ {
+ return 1;
+ }
+ protected sealed override ILInstruction GetChild(int index)
+ {
+ switch (index) {
+ case 0:
+ return this.argument;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ protected sealed override void SetChild(int index, ILInstruction value)
+ {
+ switch (index) {
+ case 0:
+ this.Argument = value;
+ break;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ protected sealed override SlotInfo GetChildSlot(int index)
+ {
+ switch (index) {
+ case 0:
+ return ArgumentSlot;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ public sealed override ILInstruction Clone()
+ {
+ var clone = (StringToInt)ShallowClone();
+ clone.Argument = this.argument.Clone();
+ return clone;
+ }
+ public override StackType ResultType { get { return StackType.I4; } }
+ protected override InstructionFlags ComputeFlags()
+ {
+ return argument.Flags;
+ }
+ public override InstructionFlags DirectFlags {
+ get {
+ return InstructionFlags.None;
+ }
+ }
+ public override void AcceptVisitor(ILVisitor visitor)
+ {
+ visitor.VisitStringToInt(this);
+ }
+ public override T AcceptVisitor(ILVisitor visitor)
+ {
+ return visitor.VisitStringToInt(this);
+ }
+ public override T AcceptVisitor(ILVisitor visitor, C context)
+ {
+ return visitor.VisitStringToInt(this, context);
+ }
+ protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
+ {
+ var o = other as StringToInt;
+ return o != null && this.argument.PerformMatch(o.argument, ref match);
+ }
+ }
+}
+namespace ICSharpCode.Decompiler.IL
{
/// Push a typed reference of type class onto the stack.
public sealed partial class MakeRefAny : UnaryInstruction
@@ -4633,6 +4716,10 @@ namespace ICSharpCode.Decompiler.IL
{
Default(inst);
}
+ protected internal virtual void VisitStringToInt(StringToInt inst)
+ {
+ Default(inst);
+ }
protected internal virtual void VisitMakeRefAny(MakeRefAny inst)
{
Default(inst);
@@ -4919,6 +5006,10 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst);
}
+ protected internal virtual T VisitStringToInt(StringToInt inst)
+ {
+ return Default(inst);
+ }
protected internal virtual T VisitMakeRefAny(MakeRefAny inst)
{
return Default(inst);
@@ -5205,6 +5296,10 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst, context);
}
+ protected internal virtual T VisitStringToInt(StringToInt inst, C context)
+ {
+ return Default(inst, context);
+ }
protected internal virtual T VisitMakeRefAny(MakeRefAny inst, C context)
{
return Default(inst, context);
@@ -5294,6 +5389,7 @@ namespace ICSharpCode.Decompiler.IL
"ldlen",
"ldelema",
"array.to.pointer",
+ "string.to.int",
"mkrefany",
"refanytype",
"refanyval",
diff --git a/ICSharpCode.Decompiler/IL/Instructions.tt b/ICSharpCode.Decompiler/IL/Instructions.tt
index 2b28a9efe..f25e3fa0d 100644
--- a/ICSharpCode.Decompiler/IL/Instructions.tt
+++ b/ICSharpCode.Decompiler/IL/Instructions.tt
@@ -220,6 +220,8 @@
new OpCode("array.to.pointer", "Converts an array pointer (O) to a reference to the first element, or to a null reference if the array is null or empty." + Environment.NewLine
+ "Also used to convert a string to a reference to the first character.",
CustomArguments("array"), ResultType("Ref")),
+ new OpCode("string.to.int", "Maps a string value to an integer. This is used in switch(string).",
+ CustomArguments("argument"), CustomConstructor, CustomWriteTo, ResultType("I4")),
new OpCode("mkrefany", "Push a typed reference of type class onto the stack.",
CustomClassName("MakeRefAny"), Unary, HasTypeOperand, ResultType("O")),
diff --git a/ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs
index f0c1b1ebc..36cd8380e 100644
--- a/ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs
+++ b/ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs
@@ -38,36 +38,4 @@ namespace ICSharpCode.Decompiler.IL
output.Write("}");
}
}
-
- ///
- /// IL using instruction.
- /// Equivalent to:
- ///
- /// stloc v(resourceExpression)
- /// try {
- /// body
- /// } finally {
- /// v?.Dispose();
- /// }
- ///
- ///
- ///
- /// The value of v is undefined after the end of the body block.
- ///
- partial class UsingInstruction
- {
- public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
- {
- output.Write("using (");
- Variable.WriteTo(output);
- output.Write(" = ");
- ResourceExpression.WriteTo(output, options);
- output.WriteLine(") {");
- output.Indent();
- Body.WriteTo(output, options);
- output.Unindent();
- output.WriteLine();
- output.Write("}");
- }
- }
}
diff --git a/ICSharpCode.Decompiler/IL/Instructions/StringToInt.cs b/ICSharpCode.Decompiler/IL/Instructions/StringToInt.cs
new file mode 100644
index 000000000..f804a3928
--- /dev/null
+++ b/ICSharpCode.Decompiler/IL/Instructions/StringToInt.cs
@@ -0,0 +1,45 @@
+// Copyright (c) 2017 Siegfried Pammer
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+
+namespace ICSharpCode.Decompiler.IL
+{
+ partial class StringToInt
+ {
+ public string[] Map { get; }
+
+ public StringToInt(ILInstruction argument, string[] map)
+ : base(OpCode.StringToInt)
+ {
+ this.Argument = argument;
+ this.Map = map;
+ }
+
+ public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
+ {
+ output.Write("string.to.int (");
+ Argument.WriteTo(output, options);
+ output.Write(", { ");
+ for (int i = 0; i < Map.Length; i++) {
+ if (i > 0) output.Write(", ");
+ output.Write($"[{i}] = \"{Map[i]}\"");
+ }
+ output.Write(" })");
+ }
+ }
+}
diff --git a/ICSharpCode.Decompiler/IL/Instructions/UsingInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/UsingInstruction.cs
new file mode 100644
index 000000000..795be5914
--- /dev/null
+++ b/ICSharpCode.Decompiler/IL/Instructions/UsingInstruction.cs
@@ -0,0 +1,53 @@
+// Copyright (c) 2017 Siegfried Pammer
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+
+namespace ICSharpCode.Decompiler.IL
+{
+ ///
+ /// IL using instruction.
+ /// Equivalent to:
+ ///
+ /// stloc v(resourceExpression)
+ /// try {
+ /// body
+ /// } finally {
+ /// v?.Dispose();
+ /// }
+ ///
+ ///
+ ///
+ /// The value of v is undefined after the end of the body block.
+ ///
+ partial class UsingInstruction
+ {
+ public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
+ {
+ output.Write("using (");
+ Variable.WriteTo(output);
+ output.Write(" = ");
+ ResourceExpression.WriteTo(output, options);
+ output.WriteLine(") {");
+ output.Indent();
+ Body.WriteTo(output, options);
+ output.Unindent();
+ output.WriteLine();
+ output.Write("}");
+ }
+ }
+}