ExpressionEmitter
using Stashbox.Expressions.Compile.Emitters;
using Stashbox.Expressions.Compile.Extensions;
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
namespace Stashbox.Expressions.Compile
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
internal static class ExpressionEmitter
{
public static bool TryEmit(this LambdaExpression expression, [System.Runtime.CompilerServices.Nullable(2)] out Delegate resultDelegate)
{
return expression.Body.TryEmit(out resultDelegate, expression.Type, expression.ReturnType, expression.Parameters.ToArray());
}
public static bool TryEmit(this Expression expression, [System.Runtime.CompilerServices.Nullable(2)] out Delegate resultDelegate, Type delegateType, Type returnType, params ParameterExpression[] parameters)
{
resultDelegate = null;
TreeAnalyzer treeAnalyzer = new TreeAnalyzer();
if (!treeAnalyzer.Analyze(expression, parameters))
return false;
object[] array = treeAnalyzer.Constants.AsArray();
if (treeAnalyzer.NestedLambdas.Length > 0)
array = array.Append(new object[treeAnalyzer.NestedLambdas.Length]);
CompilerContext compilerContext = new CompilerContext((array.Length == 0) ? null : new Closure(array), treeAnalyzer.Constants, treeAnalyzer.DefinedVariables, treeAnalyzer.CapturedParameters, treeAnalyzer.NestedLambdas);
DynamicMethod dynamicMethod = Emitter.CreateDynamicMethod(compilerContext, returnType, parameters);
ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
if (compilerContext.HasCapturedVariablesArgument) {
compilerContext.CapturedArgumentsHolderVariable = iLGenerator.PrepareCapturedArgumentsHolderVariable(treeAnalyzer.CapturedParameters.Length);
iLGenerator.CopyParametersToCapturedArgumentsIfAny(compilerContext, parameters);
}
if (treeAnalyzer.DefinedVariables.Length > 0)
compilerContext.LocalBuilders = treeAnalyzer.DefinedVariables.BuildLocals(iLGenerator);
if (!expression.TryEmit(iLGenerator, compilerContext, parameters))
return false;
iLGenerator.Emit(OpCodes.Ret);
resultDelegate = (compilerContext.HasClosure ? dynamicMethod.CreateDelegate(delegateType, compilerContext.Target) : dynamicMethod.CreateDelegate(delegateType));
return true;
}
}
}