Browse Source

Fix foreach pattern. Closes #16.

pull/37/head
Daniel Grunwald 15 years ago
parent
commit
3177b969e5
  1. 10
      ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs
  2. 8
      ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs
  3. 55
      ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs

10
ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs

@ -26,17 +26,21 @@ namespace Decompiler
/// <param name="type">The type of the new variable</param> /// <param name="type">The type of the new variable</param>
/// <param name="name">The name of the new variable</param> /// <param name="name">The name of the new variable</param>
/// <param name="allowPassIntoLoops">Whether the variable is allowed to be placed inside a loop</param> /// <param name="allowPassIntoLoops">Whether the variable is allowed to be placed inside a loop</param>
public static void DeclareVariable(AstNode node, AstType type, string name, bool allowPassIntoLoops = true) public static VariableDeclarationStatement DeclareVariable(AstNode node, AstType type, string name, bool allowPassIntoLoops = true)
{ {
VariableDeclarationStatement result = null;
AstNode pos = FindInsertPos(node, name, allowPassIntoLoops); AstNode pos = FindInsertPos(node, name, allowPassIntoLoops);
if (pos != null) { if (pos != null) {
Match m = assignmentPattern.Match(pos); Match m = assignmentPattern.Match(pos);
if (m != null && m.Get<IdentifierExpression>("ident").Single().Identifier == name) { if (m != null && m.Get<IdentifierExpression>("ident").Single().Identifier == name) {
pos.ReplaceWith(new VariableDeclarationStatement(type, name, m.Get<Expression>("init").Single().Detach())); result = new VariableDeclarationStatement(type, name, m.Get<Expression>("init").Single().Detach());
pos.ReplaceWith(result);
} else { } else {
pos.Parent.InsertChildBefore(pos, new VariableDeclarationStatement(type, name), BlockStatement.StatementRole); result = new VariableDeclarationStatement(type, name);
pos.Parent.InsertChildBefore(pos, result, BlockStatement.StatementRole);
} }
} }
return result;
} }
static AstNode FindInsertPos(AstNode node, string name, bool allowPassIntoLoops) static AstNode FindInsertPos(AstNode node, string name, bool allowPassIntoLoops)

8
ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs

@ -32,6 +32,10 @@ namespace Decompiler.Transforms
} }
} }
internal sealed class CapturedVariableAnnotation
{
}
public DelegateConstruction(DecompilerContext context) : base(context) public DelegateConstruction(DecompilerContext context) : base(context)
{ {
} }
@ -240,7 +244,9 @@ namespace Decompiler.Transforms
} }
// Now insert the variable declarations (we can do this after the replacements only so that the scope detection works): // Now insert the variable declarations (we can do this after the replacements only so that the scope detection works):
foreach (var tuple in variablesToDeclare) { foreach (var tuple in variablesToDeclare) {
DeclareVariableInSmallestScope.DeclareVariable(blockStatement, tuple.Item1, tuple.Item2, allowPassIntoLoops: false); var newVarDecl = DeclareVariableInSmallestScope.DeclareVariable(blockStatement, tuple.Item1, tuple.Item2, allowPassIntoLoops: false);
if (newVarDecl != null)
newVarDecl.Variables.Single().AddAnnotation(new CapturedVariableAnnotation());
} }
} }
return null; return null;

55
ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs

@ -103,25 +103,23 @@ namespace Decompiler.Transforms
).ToVariable() ).ToVariable()
} }
}, },
EmbeddedStatement = new BlockStatement { EmbeddedStatement = new Choice {
new ForStatement { // There are two forms of the foreach statement:
EmbeddedStatement = new BlockStatement { // one where the item variable is declared inside the loop,
new IfElseStatement { // and one where it is declared outside of the loop.
Condition = new UnaryOperatorExpression( // In the former case, we can apply the foreach pattern only if the variable wasn't captured.
UnaryOperatorType.Not, { "itemVariableInsideLoop",
new NamedNode("enumeratorIdent", new IdentifierExpression()).ToExpression().Invoke("MoveNext") new BlockStatement {
), new WhileStatement {
TrueStatement = new BlockStatement { Condition = new IdentifierExpressionBackreference("enumeratorVariable").ToExpression().Invoke("MoveNext"),
new BreakStatement() EmbeddedStatement = new BlockStatement {
},
FalseStatement = new BlockStatement {
new VariableDeclarationStatement { new VariableDeclarationStatement {
Type = new AnyNode("itemType").ToType(), Type = new AnyNode("itemType").ToType(),
Variables = { Variables = {
new NamedNode( new NamedNode(
"itemVariable", "itemVariable",
new VariableInitializer { new VariableInitializer {
Initializer = new Backreference("enumeratorIdent").ToExpression().Member("Current") Initializer = new IdentifierExpressionBackreference("enumeratorVariable").ToExpression().Member("Current")
} }
).ToVariable() ).ToVariable()
} }
@ -130,8 +128,29 @@ namespace Decompiler.Transforms
} }
} }
} }
},
{ "itemVariableOutsideLoop",
new BlockStatement {
new VariableDeclarationStatement {
Type = new AnyNode("itemType").ToType(),
Variables = {
new NamedNode("itemVariable", new VariableInitializer()).ToVariable()
}
},
new WhileStatement {
Condition = new IdentifierExpressionBackreference("enumeratorVariable").ToExpression().Invoke("MoveNext"),
EmbeddedStatement = new BlockStatement {
new AssignmentExpression {
Left = new IdentifierExpressionBackreference("itemVariable").ToExpression(),
Operator = AssignmentOperatorType.Assign,
Right = new IdentifierExpressionBackreference("enumeratorVariable").ToExpression().Member("Current")
},
new Repeat(new AnyNode("statement")).ToStatement()
}
}
}
} }
} }.ToStatement()
}; };
public void TransformForeach(AstNode compilationUnit) public void TransformForeach(AstNode compilationUnit)
@ -141,16 +160,18 @@ namespace Decompiler.Transforms
if (m == null) if (m == null)
continue; continue;
VariableInitializer enumeratorVar = m.Get<VariableInitializer>("enumeratorVariable").Single(); VariableInitializer enumeratorVar = m.Get<VariableInitializer>("enumeratorVariable").Single();
if (enumeratorVar.Name != m.Get<IdentifierExpression>("enumeratorIdent").Single().Identifier)
continue;
VariableInitializer itemVar = m.Get<VariableInitializer>("itemVariable").Single(); VariableInitializer itemVar = m.Get<VariableInitializer>("itemVariable").Single();
if (m.Has("itemVariableInsideLoop") && itemVar.Annotation<DelegateConstruction.CapturedVariableAnnotation>() != null) {
// cannot move captured variables out of loops
continue;
}
BlockStatement newBody = new BlockStatement(); BlockStatement newBody = new BlockStatement();
foreach (Statement stmt in m.Get<Statement>("statement")) foreach (Statement stmt in m.Get<Statement>("statement"))
newBody.Add(stmt.Detach()); newBody.Add(stmt.Detach());
node.ReplaceWith( node.ReplaceWith(
new ForeachStatement { new ForeachStatement {
VariableType = m.Get<AstType>("itemType").Single().Detach(), VariableType = m.Get<AstType>("itemType").Single().Detach(),
VariableName = enumeratorVar.Name, VariableName = itemVar.Name,
InExpression = m.Get<Expression>("collection").Single().Detach(), InExpression = m.Get<Expression>("collection").Single().Detach(),
EmbeddedStatement = newBody EmbeddedStatement = newBody
}); });

Loading…
Cancel
Save