Skip to content

Commit

Permalink
Attempt to derive aggregate seed/fallback parameter names from input …
Browse files Browse the repository at this point in the history
…expressions

This reverts commit eddd8c1.
  • Loading branch information
jcracknell committed Nov 16, 2024
1 parent 6f3c1b7 commit 7a2bcf3
Show file tree
Hide file tree
Showing 10 changed files with 67 additions and 40 deletions.
5 changes: 2 additions & 3 deletions src/Arborist/src/ExpressionHelper.Aggregate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@ AggregateOptions options
if(!enumerator.MoveNext())
return seed;

var parameters = enumerator.Current.Parameters;
var replacements = new Dictionary<Expression, Expression>();
var replacingVisitor = new ReplacingExpressionVisitor(replacements);
var body = seed.Body;
Expand All @@ -148,7 +147,7 @@ AggregateOptions options
var current = enumerator.Current;

replacements.Clear();
foreach(var (ps, pr) in current.Parameters.Zip(parameters))
foreach(var (ps, pr) in current.Parameters.Zip(seed.Parameters))
replacements[ps] = pr;

var right = replacingVisitor.Visit(current.Body);
Expand All @@ -167,7 +166,7 @@ AggregateOptions options
body = replacingVisitor.Visit(binaryOperator.Body);
} while(enumerator.MoveNext());

return Expression.Lambda(body, parameters);
return Expression.Lambda(body, seed.Parameters);
}
}

5 changes: 2 additions & 3 deletions src/Arborist/src/ExpressionHelper.AggregateTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,12 @@ LambdaExpression binaryOperator
case 1: return expressionList[0];
}

var parameters = expressionList[0].Parameters;
var replacements = new Dictionary<Expression, Expression>();
var replacementVisitor = new ReplacingExpressionVisitor(replacements);

return Expression.Lambda(
AggregateTreeBody(expressionList, binaryOperator, 0, expressionList.Count, parameters, replacements, replacementVisitor),
parameters
AggregateTreeBody(expressionList, binaryOperator, 0, expressionList.Count, fallback.Parameters, replacements, replacementVisitor),
fallback.Parameters
);
}

Expand Down
14 changes: 10 additions & 4 deletions src/Arborist/src/ExpressionHelper.And.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using Arborist.Internal;

namespace Arborist;

public static partial class ExpressionHelper {
Expand Down Expand Up @@ -52,11 +54,15 @@ IEnumerable<Expression<Func<A, B, C, D, bool>>> predicates
AndUnsafe(predicates);

public static Expression<TPredicate> AndUnsafe<TPredicate>(IEnumerable<Expression<TPredicate>> predicates)
where TPredicate : Delegate =>
(Expression<TPredicate>)AggregateImpl(
expressions: predicates,
seed: Const<TPredicate>(true),
where TPredicate : Delegate
{
var predicateList = CollectionHelpers.AsReadOnlyList(predicates);

return (Expression<TPredicate>)AggregateImpl(
expressions: predicateList,
seed: Const<TPredicate>(predicateList.FirstOrDefault()?.Parameters, true),
binaryOperator: ExpressionOn<bool, bool>.Of(static (a, b) => a && b),
options: new() { DiscardSeedExpression = true }
);
}
}
14 changes: 10 additions & 4 deletions src/Arborist/src/ExpressionHelper.AndTree.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using Arborist.Internal;

namespace Arborist;

public static partial class ExpressionHelper {
Expand Down Expand Up @@ -77,10 +79,14 @@ IEnumerable<Expression<Func<A, B, C, D, bool>>> predicates
AndTreeUnsafe(predicates);

public static Expression<TPredicate> AndTreeUnsafe<TPredicate>(IEnumerable<Expression<TPredicate>> predicates)
where TPredicate : Delegate =>
(Expression<TPredicate>)AggregateTreeImpl(
expressions: predicates,
fallback: Const<TPredicate>(true),
where TPredicate : Delegate
{
var predicateList = CollectionHelpers.AsReadOnlyList(predicates);

return (Expression<TPredicate>)AggregateTreeImpl(
expressions: predicateList,
fallback: Const<TPredicate>(predicateList.FirstOrDefault()?.Parameters, true),
binaryOperator: ExpressionOn<bool, bool>.Of(static (a, b) => a && b)
);
}
}
14 changes: 10 additions & 4 deletions src/Arborist/src/ExpressionHelper.Or.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using Arborist.Internal;

namespace Arborist;

public static partial class ExpressionHelper {
Expand Down Expand Up @@ -52,11 +54,15 @@ IEnumerable<Expression<Func<A, B, C, D, bool>>> predicates
OrUnsafe(predicates);

public static Expression<TPredicate> OrUnsafe<TPredicate>(IEnumerable<Expression<TPredicate>> predicates)
where TPredicate : Delegate =>
(Expression<TPredicate>)AggregateImpl(
expressions: predicates,
seed: Const<TPredicate>(false),
where TPredicate : Delegate
{
var predicateList = CollectionHelpers.AsReadOnlyList(predicates);

return (Expression<TPredicate>)AggregateImpl(
expressions: predicateList,
seed: Const<TPredicate>(predicateList.FirstOrDefault()?.Parameters, false),
binaryOperator: ExpressionOn<bool, bool>.Of(static (a, b) => a || b),
options: new() { DiscardSeedExpression = false }
);
}
}
14 changes: 10 additions & 4 deletions src/Arborist/src/ExpressionHelper.OrTree.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using Arborist.Internal;

namespace Arborist;

public static partial class ExpressionHelper {
Expand Down Expand Up @@ -77,10 +79,14 @@ IEnumerable<Expression<Func<A, B, C, D, bool>>> predicates
OrTreeUnsafe(predicates);

public static Expression<TPredicate> OrTreeUnsafe<TPredicate>(IEnumerable<Expression<TPredicate>> predicates)
where TPredicate : Delegate =>
(Expression<TPredicate>)AggregateTreeImpl(
expressions: predicates,
fallback: Const<TPredicate>(false),
where TPredicate : Delegate
{
var predicateList = CollectionHelpers.AsReadOnlyList(predicates);

return (Expression<TPredicate>)AggregateTreeImpl(
expressions: predicateList,
fallback: Const<TPredicate>(predicateList.FirstOrDefault()?.Parameters, false),
binaryOperator: ExpressionOn<bool, bool>.Of(static (a, b) => a || b)
);
}
}
25 changes: 15 additions & 10 deletions src/Arborist/src/ExpressionHelper.Predicates.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Arborist.Internal;
using Arborist.Utils;

namespace Arborist;
Expand All @@ -8,23 +9,25 @@ public static partial class ExpressionHelper {
/// together. Returns a true-valued predicate expression if the provided collection of predicates
/// is empty.
/// </summary>
public static Expression<TDelegate> And<TDelegate>(params Expression<TDelegate>[] expressions)
public static Expression<TDelegate> And<TDelegate>(params Expression<TDelegate>[] predicates)
where TDelegate : Delegate =>
And(expressions.AsEnumerable());
And(predicates.AsEnumerable());

/// <summary>
/// Combines the provided predicate expressions into a single expression by ANDing their bodies
/// together. Returns a true-valued predicate expression if the provided collection of predicates
/// is empty.
/// </summary>
public static Expression<TDelegate> And<TDelegate>(IEnumerable<Expression<TDelegate>> expressions)
public static Expression<TDelegate> And<TDelegate>(IEnumerable<Expression<TDelegate>> predicates)
where TDelegate : Delegate
{
AssertPredicateExpressionType(typeof(TDelegate));

var predicateList = CollectionHelpers.AsReadOnlyList(predicates);

return (Expression<TDelegate>)AggregateImpl(
expressions: expressions,
seed: Const<TDelegate>(true),
expressions: predicateList,
seed: Const<TDelegate>(predicateList.FirstOrDefault()?.Parameters, true),
binaryOperator: ExpressionOn<bool, bool>.Of(static (a, b) => a && b),
options: new() { DiscardSeedExpression = true }
);
Expand All @@ -35,23 +38,25 @@ public static Expression<TDelegate> And<TDelegate>(IEnumerable<Expression<TDeleg
/// together. Returns a false-valued predicate expression if the provided collection of predicates
/// is empty.
/// </summary>
public static Expression<TDelegate> Or<TDelegate>(params Expression<TDelegate>[] expressions)
public static Expression<TDelegate> Or<TDelegate>(params Expression<TDelegate>[] predicates)
where TDelegate : Delegate =>
Or(expressions.AsEnumerable());
Or(predicates.AsEnumerable());

/// <summary>
/// Combines the provided predicate expressions into a single expression by ORing their bodies
/// together. Returns a false-valued predicate expression if the provided collection of predicates
/// is empty.
/// </summary>
public static Expression<TDelegate> Or<TDelegate>(IEnumerable<Expression<TDelegate>> expressions)
public static Expression<TDelegate> Or<TDelegate>(IEnumerable<Expression<TDelegate>> predicates)
where TDelegate : Delegate
{
AssertPredicateExpressionType(typeof(TDelegate));

var predicateList = CollectionHelpers.AsReadOnlyList(predicates);

return (Expression<TDelegate>)AggregateImpl(
expressions: expressions,
seed: Const<TDelegate>(false),
expressions: predicateList,
seed: Const<TDelegate>(predicateList.FirstOrDefault()?.Parameters, false),
binaryOperator: ExpressionOn<bool, bool>.Of(static (a, b) => a || b),
options: new() { DiscardSeedExpression = true }
);
Expand Down
4 changes: 2 additions & 2 deletions src/Arborist/src/ExpressionHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ internal static bool IsFuncExpressionType(Type type) =>
internal static bool IsPredicateExpressionType(Type type) =>
IsFuncExpressionType(type) && typeof(bool) == type.GetGenericArguments()[^1];

internal static Expression<TFunc> Const<TFunc>(object? value)
internal static Expression<TFunc> Const<TFunc>(IReadOnlyCollection<ParameterExpression>? parameters, object? value)
where TFunc : Delegate
{
AssertFuncExpressionType(typeof(TFunc));
Expand All @@ -39,7 +39,7 @@ internal static Expression<TFunc> Const<TFunc>(object? value)

return Expression.Lambda<TFunc>(
Expression.Constant(value, resultType),
genericArguments[..^1].Select(Expression.Parameter)
parameters ?? genericArguments[..^1].Select(Expression.Parameter)
);
}
}
6 changes: 3 additions & 3 deletions src/Arborist/test/ExpressionHelperTests.Aggregate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public void Aggregate2_should_work_as_expected() {
ExpressionOn<Cat, Owner>.Of((c, o) => c.Name),
ExpressionOn<Cat, Owner>.Of((c, o) => o.Name)
},
seed: ExpressionOn<Cat, Owner>.Of((p0, p1) => ""),
seed: ExpressionOn<Cat, Owner>.Of((c, o) => ""),
binaryOperator: (acc, v) => acc + v
);

Expand All @@ -57,7 +57,7 @@ public void Aggregate3_should_work_as_expected() {
ExpressionOn<Cat, Owner, int>.Of((c, o, i) => o.Name),
ExpressionOn<Cat, Owner, int>.Of((c, o, i) => i.ToString())
},
seed: ExpressionOn<Cat, Owner, int>.Of((p0, p1, p2) => ""),
seed: ExpressionOn<Cat, Owner, int>.Of((c, o, i) => ""),
binaryOperator: (acc, v) => acc + v
);

Expand All @@ -74,7 +74,7 @@ public void Aggregate4_should_work_as_expected() {
ExpressionOn<Cat, Owner, int, string>.Of((c, o, i, s) => i.ToString()),
ExpressionOn<Cat, Owner, int, string>.Of((c, o, i, s) => s.ToLowerInvariant())
},
seed: ExpressionOn<Cat, Owner, int, string>.Of((p0, p1, p2, p3) => ""),
seed: ExpressionOn<Cat, Owner, int, string>.Of((c, o, i, s) => ""),
binaryOperator: (acc, v) => acc + v
);

Expand Down
6 changes: 3 additions & 3 deletions src/Arborist/test/ExpressionHelperTests.AggregateTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public void AggregateTree2_should_work_as_expected() {
ExpressionOn<Cat, Owner>.Of((c, o) => c.Name),
ExpressionOn<Cat, Owner>.Of((c, o) => o.Name)
},
fallback: ExpressionOn<Cat, Owner>.Of((p0, p1) => ""),
fallback: ExpressionOn<Cat, Owner>.Of((c, o) => ""),
binaryOperator: (acc, v) => acc + v
);

Expand All @@ -57,7 +57,7 @@ public void AggregateTree3_should_work_as_expected() {
ExpressionOn<Cat, Owner, int>.Of((c, o, i) => o.Name),
ExpressionOn<Cat, Owner, int>.Of((c, o, i) => i.ToString())
},
fallback: ExpressionOn<Cat, Owner, int>.Of((p0, p1, p2) => ""),
fallback: ExpressionOn<Cat, Owner, int>.Of((c, o, i) => ""),
binaryOperator: (acc, v) => acc + v
);

Expand All @@ -74,7 +74,7 @@ public void AggregateTree4_should_work_as_expected() {
ExpressionOn<Cat, Owner, int, string>.Of((c, o, i, s) => i.ToString()),
ExpressionOn<Cat, Owner, int, string>.Of((c, o, i, s) => s.ToLowerInvariant())
},
fallback: ExpressionOn<Cat, Owner, int, string>.Of((p0, p1, p2, p3) => ""),
fallback: ExpressionOn<Cat, Owner, int, string>.Of((c, o, i, s) => ""),
binaryOperator: (acc, v) => acc + v
);

Expand Down

0 comments on commit 7a2bcf3

Please sign in to comment.