TreeAnalyzer
class TreeAnalyzer
using Stashbox.Utils.Data;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace Stashbox.Expressions.Compile
{
internal class TreeAnalyzer
{
private bool isNestedLambda;
public ExpandableArray<Expression> CapturedParameters;
public ExpandableArray<Expression> DefinedVariables;
public ExpandableArray<LambdaExpression, NestedLambda> NestedLambdas;
public ExpandableArray<object> Constants;
public TreeAnalyzer()
{
CapturedParameters = new ExpandableArray<Expression>();
DefinedVariables = new ExpandableArray<Expression>();
NestedLambdas = new ExpandableArray<LambdaExpression, NestedLambda>();
Constants = new ExpandableArray<object>();
}
public bool Analyze(Expression expression, params ParameterExpression[] parameters)
{
switch (expression.NodeType) {
case ExpressionType.Parameter:
if (parameters.ContainsReference(expression) || DefinedVariables.IndexOf(expression) != -1)
return true;
if (!isNestedLambda)
return false;
CapturedParameters.AddOrKeep((ParameterExpression)expression);
return true;
case ExpressionType.Lambda: {
LambdaExpression lambdaExpression = (LambdaExpression)expression;
TreeAnalyzer treeAnalyzer = Clone(true);
if (!treeAnalyzer.Analyze(lambdaExpression.Body, lambdaExpression.Parameters.CastToArray()))
return false;
NestedLambdas.AddOrKeep(lambdaExpression, new NestedLambda(treeAnalyzer.DefinedVariables, treeAnalyzer.CapturedParameters.Length > 0));
return true;
}
case ExpressionType.MemberAccess:
return Analyze(((MemberExpression)expression).Expression, parameters);
case ExpressionType.Constant: {
ConstantExpression constantExpression = (ConstantExpression)expression;
if (constantExpression.Value == null || Utils.IsInPlaceEmittableConstant(constantExpression.Type, constantExpression.Value))
return true;
Constants.AddOrKeep(constantExpression.Value);
return true;
}
case ExpressionType.New:
return Analyze(((NewExpression)expression).Arguments, parameters);
case ExpressionType.MemberInit: {
MemberInitExpression memberInitExpression = (MemberInitExpression)expression;
if (Analyze(memberInitExpression.NewExpression, parameters))
return Analyze(memberInitExpression.Bindings, parameters);
return false;
}
case ExpressionType.Block: {
BlockExpression blockExpression = (BlockExpression)expression;
int count = blockExpression.Variables.Count;
for (int i = 0; i < count; i++) {
DefinedVariables.AddOrKeep(blockExpression.Variables[i]);
}
return Analyze(blockExpression.Expressions, parameters);
}
case ExpressionType.Conditional: {
ConditionalExpression conditionalExpression = (ConditionalExpression)expression;
if (Analyze(conditionalExpression.Test, parameters) && Analyze(conditionalExpression.IfTrue, parameters))
return Analyze(conditionalExpression.IfFalse, parameters);
return false;
}
case ExpressionType.Default:
return true;
case ExpressionType.Call: {
MethodCallExpression methodCallExpression = (MethodCallExpression)expression;
if (methodCallExpression.Object == null || Analyze(methodCallExpression.Object, parameters))
return Analyze(methodCallExpression.Arguments, parameters);
return false;
}
case ExpressionType.Invoke: {
InvocationExpression invocationExpression = (InvocationExpression)expression;
if (Analyze(invocationExpression.Expression, parameters))
return Analyze(invocationExpression.Arguments, parameters);
return false;
}
case ExpressionType.NewArrayInit:
return Analyze(((NewArrayExpression)expression).Expressions, parameters);
default: {
UnaryExpression unaryExpression = expression as UnaryExpression;
if (unaryExpression != null)
return Analyze(unaryExpression.Operand, parameters);
BinaryExpression binaryExpression = expression as BinaryExpression;
if (binaryExpression != null) {
if (Analyze(binaryExpression.Left, parameters))
return Analyze(binaryExpression.Right, parameters);
return false;
}
return false;
}
}
}
public TreeAnalyzer Clone(bool isLambda = false)
{
TreeAnalyzer obj = (TreeAnalyzer)MemberwiseClone();
obj.DefinedVariables = new ExpandableArray<Expression>();
obj.isNestedLambda = isLambda;
return obj;
}
private bool Analyze(IList<Expression> expressions, params ParameterExpression[] parameters)
{
int count = expressions.Count;
for (int i = 0; i < count; i++) {
if (!Analyze(expressions[i], parameters))
return false;
}
return true;
}
private bool Analyze(IList<MemberBinding> bindings, params ParameterExpression[] parameters)
{
int count = bindings.Count;
for (int i = 0; i < count; i++) {
MemberBinding memberBinding = bindings[i];
if (memberBinding.BindingType != 0 || !Analyze(((MemberAssignment)memberBinding).Expression, parameters))
return false;
}
return true;
}
}
}