Browse Source

Add support for query continuations.

pull/118/head
Daniel Grunwald 15 years ago
parent
commit
8ee23f5243
  1. 18
      ICSharpCode.Decompiler/Ast/Transforms/CombineQueryExpressions.cs
  2. 41
      ICSharpCode.Decompiler/Ast/Transforms/IntroduceQueryExpressions.cs
  3. 25
      ICSharpCode.Decompiler/Tests/QueryExpressions.cs
  4. 6
      ICSharpCode.Decompiler/Tests/TestRunner.cs

18
ICSharpCode.Decompiler/Ast/Transforms/CombineQueryExpressions.cs

@ -27,6 +27,13 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -27,6 +27,13 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
CombineQueries(compilationUnit);
}
static readonly InvocationExpression castPattern = new InvocationExpression {
Target = new MemberReferenceExpression {
Target = new AnyNode("inExpr"),
MemberName = "Cast",
TypeArguments = { new AnyNode("targetType") }
}};
void CombineQueries(AstNode node)
{
for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) {
@ -39,6 +46,17 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -39,6 +46,17 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (innerQuery != null) {
if (TryRemoveTransparentIdentifier(query, fromClause, innerQuery)) {
RemoveTransparentIdentifierReferences(query);
} else {
QueryContinuationClause continuation = new QueryContinuationClause();
continuation.PrecedingQuery = innerQuery.Detach();
continuation.Identifier = fromClause.Identifier;
fromClause.ReplaceWith(continuation);
}
} else {
Match m = castPattern.Match(fromClause.Expression);
if (m != null) {
fromClause.Type = m.Get<AstType>("targetType").Single().Detach();
fromClause.Expression = m.Get<Expression>("inExpr").Single().Detach();
}
}
}

41
ICSharpCode.Decompiler/Ast/Transforms/IntroduceQueryExpressions.cs

@ -64,6 +64,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -64,6 +64,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
void DecompileQueries(AstNode node)
{
QueryExpression query = DecompileQuery(node as InvocationExpression);
if (query != null)
node.ReplaceWith(query);
for (AstNode child = (query ?? node).FirstChild; child != null; child = child.NextSibling) {
DecompileQueries(child);
}
@ -87,26 +89,33 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -87,26 +89,33 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
QueryExpression query = new QueryExpression();
query.Clauses.Add(new QueryFromClause { Identifier = parameterName, Expression = mre.Target.Detach() });
query.Clauses.Add(new QuerySelectClause { Expression = body.Detach() });
invocation.ReplaceWith(query);
return query;
}
return null;
}
case "GroupBy":
{
if (invocation.Arguments.Count != 2)
return null;
string parameterName1, parameterName2;
Expression keySelector, elementSelector;
if (MatchSimpleLambda(invocation.Arguments.ElementAt(0), out parameterName1, out keySelector)
&& MatchSimpleLambda(invocation.Arguments.ElementAt(1), out parameterName2, out elementSelector)
&& parameterName1 == parameterName2)
{
QueryExpression query = new QueryExpression();
query.Clauses.Add(new QueryFromClause { Identifier = parameterName1, Expression = mre.Target.Detach() });
query.Clauses.Add(new QueryGroupClause { Projection = elementSelector.Detach(), Key = keySelector.Detach() });
invocation.ReplaceWith(query);
return query;
if (invocation.Arguments.Count == 2) {
string parameterName1, parameterName2;
Expression keySelector, elementSelector;
if (MatchSimpleLambda(invocation.Arguments.ElementAt(0), out parameterName1, out keySelector)
&& MatchSimpleLambda(invocation.Arguments.ElementAt(1), out parameterName2, out elementSelector)
&& parameterName1 == parameterName2)
{
QueryExpression query = new QueryExpression();
query.Clauses.Add(new QueryFromClause { Identifier = parameterName1, Expression = mre.Target.Detach() });
query.Clauses.Add(new QueryGroupClause { Projection = elementSelector.Detach(), Key = keySelector.Detach() });
return query;
}
} else if (invocation.Arguments.Count == 1) {
string parameterName;
Expression keySelector;
if (MatchSimpleLambda(invocation.Arguments.Single(), out parameterName, out keySelector)) {
QueryExpression query = new QueryExpression();
query.Clauses.Add(new QueryFromClause { Identifier = parameterName, Expression = mre.Target.Detach() });
query.Clauses.Add(new QueryGroupClause { Projection = new IdentifierExpression(parameterName), Key = keySelector.Detach() });
return query;
}
}
return null;
}
@ -127,7 +136,6 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -127,7 +136,6 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
query.Clauses.Add(new QueryFromClause { Identifier = p1.Name, Expression = mre.Target.Detach() });
query.Clauses.Add(new QueryFromClause { Identifier = p2.Name, Expression = collectionSelector.Detach() });
query.Clauses.Add(new QuerySelectClause { Expression = ((Expression)lambda.Body).Detach() });
invocation.ReplaceWith(query);
return query;
}
}
@ -143,7 +151,6 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -143,7 +151,6 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
QueryExpression query = new QueryExpression();
query.Clauses.Add(new QueryFromClause { Identifier = parameterName, Expression = mre.Target.Detach() });
query.Clauses.Add(new QueryWhereClause { Condition = body.Detach() });
invocation.ReplaceWith(query);
return query;
}
return null;
@ -183,7 +190,6 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -183,7 +190,6 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
QueryExpression query = new QueryExpression();
query.Clauses.Add(new QueryFromClause { Identifier = parameterName, Expression = mre.Target.Detach() });
query.Clauses.Add(orderClause);
invocation.ReplaceWith(query);
return query;
}
}
@ -219,7 +225,6 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -219,7 +225,6 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
}
query.Clauses.Add(joinClause);
query.Clauses.Add(new QuerySelectClause { Expression = ((Expression)lambda.Body).Detach() });
invocation.ReplaceWith(query);
return query;
}
}

25
ICSharpCode.Decompiler/Tests/QueryExpressions.cs

@ -10,9 +10,10 @@ public class QueryExpressions @@ -10,9 +10,10 @@ public class QueryExpressions
public class Customer
{
public int CustomerID;
public IEnumerable<Order> Orders;
public IEnumerable<QueryExpressions.Order> Orders;
public string Name;
public string Country;
public string City;
}
public class Order
@ -22,7 +23,7 @@ public class QueryExpressions @@ -22,7 +23,7 @@ public class QueryExpressions
public Customer Customer;
public int CustomerID;
public decimal Total;
public IEnumerable<OrderDetail> Details;
public IEnumerable<QueryExpressions.OrderDetail> Details;
}
public class OrderDetail
@ -31,8 +32,8 @@ public class QueryExpressions @@ -31,8 +32,8 @@ public class QueryExpressions
public int Quantity;
}
public IEnumerable<Customer> customers;
public IEnumerable<Order> orders;
public IEnumerable<QueryExpressions.Customer> customers;
public IEnumerable<QueryExpressions.Order> orders;
public object MultipleWhere()
{
@ -129,4 +130,20 @@ public class QueryExpressions @@ -129,4 +130,20 @@ public class QueryExpressions
from c in customers
group c.Name by c.Country;
}
public object ExplicitType()
{
return
from Customer c in customers
where c.City == "London"
select c;
}
public object QueryContinuation()
{
return
from c in customers
group c by c.Country into g
select new { Country = g.Key, CustCount = g.Count() };
}
}

6
ICSharpCode.Decompiler/Tests/TestRunner.cs

@ -94,6 +94,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -94,6 +94,12 @@ namespace ICSharpCode.Decompiler.Tests
TestFile(@"..\..\Tests\YieldReturn.cs");
}
[Test, Ignore("Formatting differences")]
public void QueryExpressions()
{
TestFile(@"..\..\Tests\QueryExpressions.cs");
}
static void TestFile(string fileName)
{
string code = File.ReadAllText(fileName);

Loading…
Cancel
Save