Skip to content

Commit

Permalink
Refactor back to plain static methods
Browse files Browse the repository at this point in the history
  • Loading branch information
jcracknell committed Nov 3, 2024
1 parent dd9f268 commit 81f987e
Show file tree
Hide file tree
Showing 27 changed files with 486 additions and 661 deletions.
81 changes: 81 additions & 0 deletions src/Arborist/src/ExpressionHelper.Interpolate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using Arborist.Internal;

namespace Arborist;

public static partial class ExpressionHelper {
internal static Expression<TDelegate> InterpolateCore<TData, TDelegate>(TData data, LambdaExpression expression)
where TDelegate : Delegate
{
var analyzer = new AnalyzingInterpolationVisitor(expression);
analyzer.Visit(expression.Body);

var parameterExpressions = expression.Parameters.Skip(1);

var interpolator = new SplicingInterpolationVisitor(
evaluatedSpliceParameters: EvaluateInterpolatedExpressions(
data: data,
evaluatedExpressions: analyzer.EvaluatedExpressions,
dataReferences: analyzer.DataReferences
)
);

return Expression.Lambda<TDelegate>(
body: interpolator.Visit(expression.Body),
parameters: expression.Parameters.Skip(1)
);
}

private static IReadOnlyDictionary<Expression, object?> EvaluateInterpolatedExpressions<TData>(
TData data,
IReadOnlySet<Expression> evaluatedExpressions,
IReadOnlySet<MemberExpression> dataReferences
) {
if(evaluatedExpressions.Count == 0)
return ImmutableDictionary<Expression, object?>.Empty;

var unevaluatedExpressions = default(List<Expression>);
var evaluatedValues = new Dictionary<Expression, object?>(evaluatedExpressions.Count);
foreach(var expr in evaluatedExpressions) {
switch(expr) {
case ConstantExpression { Value: var value }:
evaluatedValues[expr] = value;
break;
case UnaryExpression { NodeType: ExpressionType.Convert, Operand: ConstantExpression { Value: var value } }:
evaluatedValues[expr] = value;
break;
default:
(unevaluatedExpressions ??= new(evaluatedExpressions.Count - evaluatedValues.Count)).Add(expr);
break;
}
}

// If there are no expressions requiring evaluation, then we can skip costly evaluation
if(unevaluatedExpressions is not { Count: not 0 })
return evaluatedValues;

var dataParameter = Expression.Parameter(typeof(TData));

// Build a dictionary mapping references to ISplicingContext.Data with the data parameter
var dataReferenceReplacements = new Dictionary<Expression, Expression>(dataReferences.Count);
foreach(var dataReference in dataReferences)
dataReferenceReplacements[dataReference] = dataParameter;

var evaluated = Expression.Lambda<Func<TData, object?[]>>(
Expression.NewArrayInit(typeof(object),
from expr in unevaluatedExpressions select Expression.Convert(
ExpressionHelper.Replace(expr, dataReferenceReplacements),
typeof(object)
)
),
dataParameter
)
.Compile()
.Invoke(data);

for(var i = 0; i < unevaluatedExpressions.Count; i++)
evaluatedValues[unevaluatedExpressions[i]] = evaluated[i];

return evaluatedValues;
}

}
30 changes: 0 additions & 30 deletions src/Arborist/src/ExpressionHelper.cs
Original file line number Diff line number Diff line change
@@ -1,36 +1,6 @@
namespace Arborist;

public static partial class ExpressionHelper {
/// <summary>
/// Helpers for expressions accepting no parameters.
/// </summary>
public static IExpressionHelperOnNone OnNone =>
ExpressionHelperOnNone.Instance;

/// <summary>
/// Helpers for expressions accepting a single parameter.
/// </summary>
public static IExpressionHelperOn<A> On<A>() =>
ExpressionHelperOn<A>.Instance;

/// <summary>
/// Helpers for expressions accepting two parameters.
/// </summary>
public static IExpressionHelperOn<A, B> On<A, B>() =>
ExpressionHelperOn<A, B>.Instance;

/// <summary>
/// Helpers for expressions accepting 3 parameters.
/// </summary>
public static IExpressionHelperOn<A, B, C> On<A, B, C>() =>
ExpressionHelperOn<A, B, C>.Instance;

/// <summary>
/// Helpers for expressions accepting 4 parameters.
/// </summary>
public static IExpressionHelperOn<A, B, C, D> On<A, B, C, D>() =>
ExpressionHelperOn<A, B, C, D>.Instance;

internal static void AssertActionExpressionType(Type type) {
if(!IsActionExpressionType(type))
throw new InvalidOperationException($"Invalid Action type: {type}.");
Expand Down
31 changes: 0 additions & 31 deletions src/Arborist/src/ExpressionHelperExtensions.Graft.cs

This file was deleted.

221 changes: 0 additions & 221 deletions src/Arborist/src/ExpressionHelperExtensions.Interpolate.cs

This file was deleted.

Loading

0 comments on commit 81f987e

Please sign in to comment.