Browse Source

Add foreach pattern. Closes #16.

pull/37/head
Daniel Grunwald 15 years ago
parent
commit
e7efab1f5b
  1. 6
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  2. 82
      ICSharpCode.Decompiler/Ast/Transforms/UsingStatementTransform.cs
  3. 8
      ICSharpCode.Decompiler/Tests/Loops.cs

6
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -78,9 +78,9 @@ namespace Decompiler @@ -78,9 +78,9 @@ namespace Decompiler
Ast.BlockStatement astBlock = new BlockStatement();
if (block != null) {
if (block.EntryGoto != null)
astBlock.AddStatement((Statement)TransformExpression(block.EntryGoto));
astBlock.Add((Statement)TransformExpression(block.EntryGoto));
foreach(ILNode node in block.Body) {
astBlock.AddStatements(TransformNode(node));
astBlock.AddRange(TransformNode(node));
}
}
return astBlock;
@ -291,7 +291,7 @@ namespace Decompiler @@ -291,7 +291,7 @@ namespace Decompiler
BlockStatement branchCommand = null;
if (byteCode.Operand is ILLabel) {
branchCommand = new BlockStatement();
branchCommand.AddStatement(new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name));
branchCommand.Add(new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name));
}
switch((Code)opCode) {

82
ICSharpCode.Decompiler/Ast/Transforms/UsingStatementTransform.cs

@ -15,6 +15,13 @@ namespace Decompiler.Transforms @@ -15,6 +15,13 @@ namespace Decompiler.Transforms
/// </summary>
public class UsingStatementTransform : IAstTransform
{
public void Run(AstNode compilationUnit)
{
TransformUsings(compilationUnit);
TransformForeach(compilationUnit);
}
#region using
static readonly AstNode usingVarDeclPattern = new VariableDeclarationStatement {
Type = new AnyNode("type").ToType(),
Variables = {
@ -35,7 +42,6 @@ namespace Decompiler.Transforms @@ -35,7 +42,6 @@ namespace Decompiler.Transforms
static readonly AstNode usingTryCatchPattern = new TryCatchStatement {
TryBlock = new AnyNode("body").ToBlock(),
FinallyBlock = new BlockStatement {
Statements = {
new Choice {
{ "valueType",
new ExpressionStatement(new NamedNode("ident", new IdentifierExpression()).ToExpression().Invoke("Dispose"))
@ -48,18 +54,15 @@ namespace Decompiler.Transforms @@ -48,18 +54,15 @@ namespace Decompiler.Transforms
new NullReferenceExpression()
),
TrueStatement = new BlockStatement {
Statements = {
new ExpressionStatement(new Backreference("ident").ToExpression().Invoke("Dispose"))
}
}
}
}
}.ToStatement()
}
}
};
public void Run(AstNode compilationUnit)
public void TransformUsings(AstNode compilationUnit)
{
foreach (AstNode node in compilationUnit.Descendants.ToArray()) {
Match m1 = usingVarDeclPattern.Match(node);
@ -85,5 +88,74 @@ namespace Decompiler.Transforms @@ -85,5 +88,74 @@ namespace Decompiler.Transforms
}
}
}
#endregion
#region foreach
UsingStatement foreachPattern = new UsingStatement {
ResourceAcquisition = new VariableDeclarationStatement {
Type = new AnyNode("enumeratorType").ToType(),
Variables = {
new NamedNode(
"enumeratorVariable",
new VariableInitializer {
Initializer = new AnyNode("collection").ToExpression().Invoke("GetEnumerator")
}
).ToVariable()
}
},
EmbeddedStatement = new BlockStatement {
new ForStatement {
EmbeddedStatement = new BlockStatement {
new IfElseStatement {
Condition = new UnaryOperatorExpression(
UnaryOperatorType.Not,
new NamedNode("enumeratorIdent", new IdentifierExpression()).ToExpression().Invoke("MoveNext")
),
TrueStatement = new BlockStatement {
new BreakStatement()
},
FalseStatement = new BlockStatement {
new VariableDeclarationStatement {
Type = new AnyNode("itemType").ToType(),
Variables = {
new NamedNode(
"itemVariable",
new VariableInitializer {
Initializer = new Backreference("enumeratorIdent").ToExpression().Member("Current")
}
).ToVariable()
}
},
new Repeat(new AnyNode("statement")).ToStatement()
}
}
}
}
}
};
public void TransformForeach(AstNode compilationUnit)
{
foreach (AstNode node in compilationUnit.Descendants.ToArray()) {
Match m = foreachPattern.Match(node);
if (m == null)
continue;
VariableInitializer enumeratorVar = m.Get<VariableInitializer>("enumeratorVariable").Single();
if (enumeratorVar.Name != m.Get<IdentifierExpression>("enumeratorIdent").Single().Identifier)
continue;
VariableInitializer itemVar = m.Get<VariableInitializer>("itemVariable").Single();
BlockStatement newBody = new BlockStatement();
foreach (Statement stmt in m.Get<Statement>("statement"))
newBody.Add(stmt.Detach());
node.ReplaceWith(
new ForeachStatement {
VariableType = m.Get<AstType>("itemType").Single().Detach(),
VariableName = enumeratorVar.Name,
InExpression = m.Get<Expression>("collection").Single().Detach(),
EmbeddedStatement = newBody
});
}
}
#endregion
}
}

8
ICSharpCode.Decompiler/Tests/Loops.cs

@ -13,6 +13,14 @@ public class Loops @@ -13,6 +13,14 @@ public class Loops
}
}
public void ForEachOverList(List<string> list)
{
// List has a struct as enumerator, so produces quite different IL than foreach over the IEnumerable interface
foreach (string text in list) {
text.ToLower();
}
}
public void ForEachOverArray(string[] array)
{
foreach (string text in array) {

Loading…
Cancel
Save