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

25
ICSharpCode.Decompiler/Tests/QueryExpressions.cs

@ -10,9 +10,10 @@ public class QueryExpressions
public class Customer public class Customer
{ {
public int CustomerID; public int CustomerID;
public IEnumerable<Order> Orders; public IEnumerable<QueryExpressions.Order> Orders;
public string Name; public string Name;
public string Country; public string Country;
public string City;
} }
public class Order public class Order
@ -22,7 +23,7 @@ public class QueryExpressions
public Customer Customer; public Customer Customer;
public int CustomerID; public int CustomerID;
public decimal Total; public decimal Total;
public IEnumerable<OrderDetail> Details; public IEnumerable<QueryExpressions.OrderDetail> Details;
} }
public class OrderDetail public class OrderDetail
@ -31,8 +32,8 @@ public class QueryExpressions
public int Quantity; public int Quantity;
} }
public IEnumerable<Customer> customers; public IEnumerable<QueryExpressions.Customer> customers;
public IEnumerable<Order> orders; public IEnumerable<QueryExpressions.Order> orders;
public object MultipleWhere() public object MultipleWhere()
{ {
@ -129,4 +130,20 @@ public class QueryExpressions
from c in customers from c in customers
group c.Name by c.Country; 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
TestFile(@"..\..\Tests\YieldReturn.cs"); TestFile(@"..\..\Tests\YieldReturn.cs");
} }
[Test, Ignore("Formatting differences")]
public void QueryExpressions()
{
TestFile(@"..\..\Tests\QueryExpressions.cs");
}
static void TestFile(string fileName) static void TestFile(string fileName)
{ {
string code = File.ReadAllText(fileName); string code = File.ReadAllText(fileName);

Loading…
Cancel
Save