/// <summary>Resolve parameters used for the code or expression.</summary> /// <param name="scope">The expression scope for the code or expression to compile.</param> /// <param name="parameterTypes">The dictionary of parameters (name / type) used in the code or expression to compile.</param> /// <returns>A ParameterExpression list used in code or expression to compile.</returns> private static List<ParameterExpression> ResolveParameter(ExpressionScope scope, IDictionary<string, Type> parameterTypes) { var parameters = new List<ParameterExpression>(); var parameterDictionary = scope.CreateParameter(typeof (IDictionary)); parameters.Add(parameterDictionary); foreach (var parameter in parameterTypes) { #if SQLNET scope.CreateLazyVariable(parameter.Key, new LazySingleThread<Expression>(() => #else scope.CreateLazyVariable(parameter.Key, new Lazy<Expression>(() => #endif { var innerParameter = scope.CreateVariable(parameter.Value, parameter.Key); Expression innerExpression = Expression.Property(parameterDictionary, DictionaryItemPropertyInfo, Expression.Constant(parameter.Key)); innerExpression = innerExpression.Type != parameter.Value ? Expression.Assign(innerParameter, Expression.Convert(innerExpression, parameter.Value)) : Expression.Assign(innerParameter, innerExpression); scope.Expressions.Add(Expression.Assign(innerParameter, innerExpression)); return innerParameter; })); } return parameters; }
/// <summary>Resolve dictionary parameters used for the code or expression.</summary> /// <param name="scope">The expression scope for the code or expression to compile.</param> /// <param name="parameterTypes">The dictionary of parameter (name / type) used in the code or expression to compile.</param> /// <returns>A ParameterExpression list used in code or expression to compile.</returns> private static List <ParameterExpression> ResolveParameterDictionary(ExpressionScope scope, IDictionary <string, Type> parameterTypes) { var parameters = new List <ParameterExpression>(); var parameterDictionary = scope.CreateParameter(typeof(IDictionary)); parameters.Add(parameterDictionary); foreach (var parameter in parameterTypes) { scope.CreateLazyVariable(parameter.Key, new Lazy <Expression>(() => { var innerParameter = scope.CreateVariable(parameter.Value, parameter.Key); Expression innerExpression = Expression.Property(parameterDictionary, DictionaryItemPropertyInfo, Expression.Constant(parameter.Key)); innerExpression = innerExpression.Type != parameter.Value ? Expression.Assign(innerParameter, Expression.Convert(innerExpression, parameter.Value)) : Expression.Assign(innerParameter, innerExpression); scope.Expressions.Add(Expression.Assign(innerParameter, innerExpression)); return(innerParameter); })); } return(parameters); }
/// <summary>Resolve enumerable parameters used for the code or expression.</summary> /// <param name="scope">The expression scope for the code or expression to compile.</param> /// <param name="parameterTypes">The dictionary of parameter (name / type) used in the code or expression to compile.</param> /// <returns>A ParameterExpression list used in code or expression to compile.</returns> private static List<ParameterExpression> ResolveParameterEnumerable(ExpressionScope scope, IDictionary<string, Type> parameterTypes) { var parameters = new List<ParameterExpression>(); var parameterEnumerable = scope.CreateParameter(typeof (IEnumerable)); parameters.Add(parameterEnumerable); var dictParameter = scope.CreateVariable(typeof (Dictionary<string, object>)); var methodConvert = typeof (EvalCompiler).GetMethod("ResolveToParameterDictionary", BindingFlags.NonPublic | BindingFlags.Static); var expressionConvert = Expression.Call(methodConvert, new Expression[] {parameterEnumerable}); var expressionAssign = Expression.Assign(dictParameter, expressionConvert); scope.Expressions.Add(expressionAssign); foreach (var parameter in parameterTypes) { scope.CreateLazyVariable(parameter.Key, new LazySingleThread<Expression>(() => { var innerParameter = scope.CreateVariable(parameter.Value, parameter.Key); Expression innerExpression = Expression.Property(dictParameter, DictionaryItemPropertyInfo, Expression.Constant(parameter.Key)); innerExpression = innerExpression.Type != parameter.Value ? Expression.Assign(innerParameter, Expression.Convert(innerExpression, parameter.Value)) : Expression.Assign(innerParameter, innerExpression); scope.Expressions.Add(Expression.Assign(innerParameter, innerExpression)); return innerParameter; })); } return parameters; }
/// <summary>Resolve untyped parameters used for the code or expression.</summary> /// <param name="scope">The expression scope for the code or expression to compile.</param> /// <param name="parameterTypes">The dictionary of parameter (name / type) used in the code or expression to compile.</param> /// <returns>A ParameterExpression list used in code or expression to compile.</returns> private static List<ParameterExpression> ResolveParameterUntyped(ExpressionScope scope, IDictionary<string, Type> parameterTypes, bool forceFirstParameterProperty = false) { var parameters = new List<ParameterExpression>(); foreach (var parameter in parameterTypes) { var parameterExpression = scope.CreateParameter(typeof (object)); parameters.Add(parameterExpression); scope.CreateLazyVariable(parameter.Key, new Lazy<Expression>(() => { var innerParameter = scope.CreateVariable(parameter.Value, parameter.Key); var innerExpression = parameterExpression.Type != parameter.Value ? Expression.Assign(innerParameter, Expression.Convert(parameterExpression, parameter.Value)) : Expression.Assign(innerParameter, parameterExpression); scope.Expressions.Insert(0, innerExpression); return innerParameter; })); } if (parameterTypes.Count == 1 || (parameterTypes.Count > 0 && forceFirstParameterProperty)) { var keyValue = parameterTypes.First(); if (Type.GetTypeCode(keyValue.Value) == TypeCode.Object) { ResolzeLazyMember(scope, parameterTypes, keyValue.Key, keyValue.Value); } } return parameters; }
/// <summary>Resolve enumerable parameters used for the code or expression.</summary> /// <param name="scope">The expression scope for the code or expression to compile.</param> /// <param name="parameterTypes">The dictionary of parameter (name / type) used in the code or expression to compile.</param> /// <returns>A ParameterExpression list used in code or expression to compile.</returns> private static List <ParameterExpression> ResolveParameterEnumerable(ExpressionScope scope, IDictionary <string, Type> parameterTypes) { var parameters = new List <ParameterExpression>(); var parameterEnumerable = scope.CreateParameter(typeof(IEnumerable)); parameters.Add(parameterEnumerable); var dictParameter = scope.CreateVariable(typeof(Dictionary <string, object>)); var methodConvert = typeof(EvalCompiler).GetMethod("ResolveToParameterDictionary", BindingFlags.NonPublic | BindingFlags.Static); var expressionConvert = Expression.Call(methodConvert, new Expression[] { parameterEnumerable }); var expressionAssign = Expression.Assign(dictParameter, expressionConvert); scope.Expressions.Add(expressionAssign); foreach (var parameter in parameterTypes) { scope.CreateLazyVariable(parameter.Key, new Lazy <Expression>(() => { var innerParameter = scope.CreateVariable(parameter.Value, parameter.Key); Expression innerExpression = Expression.Property(dictParameter, DictionaryItemPropertyInfo, Expression.Constant(parameter.Key)); innerExpression = innerExpression.Type != parameter.Value ? Expression.Assign(innerParameter, Expression.Convert(innerExpression, parameter.Value)) : Expression.Assign(innerParameter, innerExpression); scope.Expressions.Add(Expression.Assign(innerParameter, innerExpression)); return(innerParameter); })); } return(parameters); }
/// <summary>Resolve untyped parameters used for the code or expression.</summary> /// <param name="scope">The expression scope for the code or expression to compile.</param> /// <param name="parameterTypes">The dictionary of parameter (name / type) used in the code or expression to compile.</param> /// <returns>A ParameterExpression list used in code or expression to compile.</returns> private static List <ParameterExpression> ResolveParameterUntyped(ExpressionScope scope, IDictionary <string, Type> parameterTypes) { var parameters = new List <ParameterExpression>(); foreach (var parameter in parameterTypes) { var parameterExpression = scope.CreateParameter(typeof(object)); parameters.Add(parameterExpression); scope.CreateLazyVariable(parameter.Key, new LazySingleThread <Expression>(() => { var innerParameter = scope.CreateVariable(parameter.Value, parameter.Key); var innerExpression = parameterExpression.Type != parameter.Value ? Expression.Assign(innerParameter, Expression.Convert(parameterExpression, parameter.Value)) : Expression.Assign(innerParameter, parameterExpression); scope.Expressions.Insert(0, innerExpression); return(innerParameter); })); } if (parameterTypes.Count == 1) { var keyValue = parameterTypes.First(); if (Type.GetTypeCode(keyValue.Value) == TypeCode.Object) { ResolzeLazyMember(scope, parameterTypes, keyValue.Key, keyValue.Value); } } return(parameters); }
/// <summary>Resolve single object parameters used for the code or expression.</summary> /// <param name="scope">The expression scope for the code or expression to compile.</param> /// <param name="parameterTypes">The dictionary of parameter (name / type) used in the code or expression to compile.</param> /// <returns>A ParameterExpression list used in code or expression to compile.</returns> private static List<ParameterExpression> ResolveParameterSingleObject(ExpressionScope scope, IDictionary<string, Type> parameterTypes) { var parameters = new List<ParameterExpression>(); var parameterExpression = scope.CreateParameter(typeof (object)); parameters.Add(parameterExpression); var parameterObjectType = parameterTypes["{0}"]; var parameterObject = scope.CreateVariable(parameterObjectType, "{0}"); scope.Expressions.Add(Expression.Assign(parameterObject, Expression.Convert(parameterExpression, parameterObjectType))); foreach (var parameter in parameterTypes) { scope.CreateLazyVariable(parameter.Key, new Lazy<Expression>(() => { var innerParameter = scope.CreateVariable(parameter.Value, parameter.Key); var property = parameterObjectType.GetProperty(parameter.Key); Expression innerExpression = property != null ? Expression.Property(parameterObject, property) : Expression.Field(parameterObject, parameterObjectType.GetField(parameter.Key)); innerExpression = innerExpression.Type != parameter.Value ? Expression.Assign(innerParameter, Expression.Convert(innerExpression, parameter.Value)) : Expression.Assign(innerParameter, innerExpression); scope.Expressions.Add(Expression.Assign(innerParameter, innerExpression)); return innerParameter; })); } return parameters; }
/// <summary>Resolve lazy member from the member type</summary> /// <param name="scope">The expression scope for the code or expression to compile.</param> /// <param name="parameterTypes">The dictionary of parameter (name / type) used in the code or expression to compile.</param> /// <param name="parameterName">The main parameter name.</param> /// <param name="memberType">The member type.</param> private static void ResolzeLazyMember(ExpressionScope scope, IDictionary <string, Type> parameterTypes, string parameterName, Type memberType) { if (Type.GetTypeCode(memberType) == TypeCode.Object) { var parameterProperties = memberType.GetProperties().Where(x => x.GetIndexParameters().Count() == 0).ToArray(); var parameterFields = memberType.GetFields(); var instanceMethods = memberType.GetMethods(); foreach (var propertyInfo in parameterProperties) { parameterTypes.Add(propertyInfo.Name, propertyInfo.PropertyType); scope.CreateLazyVariable(propertyInfo.Name, new Lazy <Expression>(() => { var innerParameter = scope.CreateVariable(propertyInfo.PropertyType, propertyInfo.Name); var innerExpression = Expression.Assign(innerParameter, Expression.Property(scope.GetValueExpressionOrNull(parameterName), propertyInfo)); scope.Expressions.Add(innerExpression); return(innerParameter); })); } foreach (var fieldInfo in parameterFields) { parameterTypes.Add(fieldInfo.Name, fieldInfo.FieldType); scope.CreateLazyVariable(fieldInfo.Name, new Lazy <Expression>(() => { var innerParameter = scope.CreateVariable(fieldInfo.FieldType, fieldInfo.Name); var innerExpression = Expression.Assign(innerParameter, Expression.Field(scope.GetValueExpressionOrNull(parameterName), fieldInfo)); scope.Expressions.Add(innerExpression); return(innerParameter); })); } foreach (var method in instanceMethods) { scope.InstanceMethods.Add(method, parameterName); } } }
/// <summary>Resolve lazy member from the member type</summary> /// <param name="scope">The expression scope for the code or expression to compile.</param> /// <param name="parameterTypes">The dictionary of parameter (name / type) used in the code or expression to compile.</param> /// <param name="parameterName">The main parameter name.</param> /// <param name="memberType">The member type.</param> private static void ResolzeLazyMember(ExpressionScope scope, IDictionary<string, Type> parameterTypes, string parameterName, Type memberType) { if (Type.GetTypeCode(memberType) == TypeCode.Object) { var parameterProperties = memberType.GetProperties().Where(x => x.GetIndexParameters().Count() == 0).ToArray(); var parameterFields = memberType.GetFields(); var instanceMethods = memberType.GetMethods(); foreach (var propertyInfo in parameterProperties) { parameterTypes.Add(propertyInfo.Name, propertyInfo.PropertyType); scope.CreateLazyVariable(propertyInfo.Name, new Lazy<Expression>(() => { var innerParameter = scope.CreateVariable(propertyInfo.PropertyType, propertyInfo.Name); var innerExpression = Expression.Assign(innerParameter, Expression.Property(scope.GetValueExpressionOrNull(parameterName), propertyInfo)); scope.Expressions.Add(innerExpression); return innerParameter; })); } foreach (var fieldInfo in parameterFields) { parameterTypes.Add(fieldInfo.Name, fieldInfo.FieldType); scope.CreateLazyVariable(fieldInfo.Name, new Lazy<Expression>(() => { var innerParameter = scope.CreateVariable(fieldInfo.FieldType, fieldInfo.Name); var innerExpression = Expression.Assign(innerParameter, Expression.Field(scope.GetValueExpressionOrNull(parameterName), fieldInfo)); scope.Expressions.Add(innerExpression); return innerParameter; })); } foreach (var method in instanceMethods) { scope.InstanceMethods.Add(method, parameterName); } } }
/// <summary>Resolve single object parameters used for the code or expression.</summary> /// <param name="scope">The expression scope for the code or expression to compile.</param> /// <param name="parameterTypes">The dictionary of parameter (name / type) used in the code or expression to compile.</param> /// <returns>A ParameterExpression list used in code or expression to compile.</returns> private static List <ParameterExpression> ResolveParameterSingleObject(ExpressionScope scope, IDictionary <string, Type> parameterTypes) { var parameters = new List <ParameterExpression>(); var parameterExpression = scope.CreateParameter(typeof(object)); parameters.Add(parameterExpression); var parameterObjectType = parameterTypes["{0}"]; var parameterObject = scope.CreateVariable(parameterObjectType, "{0}"); scope.Expressions.Add(Expression.Assign(parameterObject, Expression.Convert(parameterExpression, parameterObjectType))); foreach (var parameter in parameterTypes) { scope.CreateLazyVariable(parameter.Key, new Lazy <Expression>(() => { var innerParameter = scope.CreateVariable(parameter.Value, parameter.Key); var property = parameterObjectType.GetProperty(parameter.Key); Expression innerExpression = property != null ? Expression.Property(parameterObject, property) : Expression.Field(parameterObject, parameterObjectType.GetField(parameter.Key)); innerExpression = innerExpression.Type != parameter.Value ? Expression.Assign(innerParameter, Expression.Convert(innerExpression, parameter.Value)) : Expression.Assign(innerParameter, innerExpression); scope.Expressions.Add(Expression.Assign(innerParameter, innerExpression)); return(innerParameter); })); } return(parameters); }
/// <summary>Resolve single dictionary parameters used for the code or expression.</summary> /// <param name="scope">The expression scope for the code or expression to compile.</param> /// <param name="parameterTypes">The dictionary of parameter (name / type) used in the code or expression to compile.</param> /// <returns>A ParameterExpression list used in code or expression to compile.</returns> private static List <ParameterExpression> ResolveParameterSingleDictionary(ExpressionScope scope, IDictionary <string, Type> parameterTypes, bool forceFirstParameterProperty = false) { var parameters = new List <ParameterExpression>(); var parameterDictionary = scope.CreateParameter(typeof(IDictionary), "{0}"); parameters.Add(parameterDictionary); foreach (var parameter in parameterTypes) { scope.CreateLazyVariable(parameter.Key, new Lazy <Expression>(() => { var innerParameter = scope.CreateVariable(parameter.Value, parameter.Key); Expression innerExpression = Expression.Property(parameterDictionary, DictionaryItemPropertyInfo, Expression.Constant(parameter.Key)); innerExpression = innerExpression.Type != parameter.Value ? Expression.Assign(innerParameter, Expression.Convert(innerExpression, parameter.Value)) : Expression.Assign(innerParameter, innerExpression); scope.Expressions.Add(Expression.Assign(innerParameter, innerExpression)); return(innerParameter); })); } if (parameterTypes.Count > 0 && forceFirstParameterProperty) { var keyValue = parameterTypes.First(); if (Type.GetTypeCode(keyValue.Value) == TypeCode.Object) { ResolzeLazyMember(scope, parameterTypes, keyValue.Key, keyValue.Value); } } return(parameters); }
/// <summary>Compile the code or expression and return a TDelegate of type Func or Action to execute.</summary> /// <typeparam name="TDelegate">Type of the delegate (Func or Action) to use to compile the code or expression.</typeparam> /// <param name="context">The eval context used to compile the code or expression.</param> /// <param name="code">The code or expression to compile.</param> /// <param name="parameterTypes">The dictionary of parameter (name / type) used in the code or expression to compile.</param> /// <param name="resultType">Type of the compiled code or expression result.</param> /// <param name="parameterKind">The parameter kind for the code or expression to compile.</param> /// <returns>A TDelegate of type Func or Action that represents the compiled code or expression.</returns> internal static TDelegate Compile <TDelegate>(EvalContext context, string code, IDictionary <string, Type> parameterTypes, Type resultType, EvalCompilerParameterKind parameterKind) { var cacheKey = context.UseCache ? ResolveCacheKey(context, typeof(TDelegate), code, parameterTypes) : ""; if (context.UseCache) { var item = EvalManager.Cache.Get(cacheKey); if (item != null) { return((TDelegate)item); } } // Options var scope = new ExpressionScope { AliasExtensionMethods = context.AliasExtensionMethods, //AliasGlobalConstants = context.AliasGlobalConstants, //AliasGlobalVariables = context.AliasGlobalVariables, AliasNames = context.AliasNames, AliasStaticMembers = context.AliasStaticMembers, AliasTypes = context.AliasTypes, BindingFlags = context.BindingFlags, UseCaretForExponent = context.UseCaretForExponent }; // Resolve Parameter var parameterExpressions = ResolveParameter(scope, parameterKind, parameterTypes); // ADD global constants if (context.AliasGlobalConstants.Count > 0) { scope.Constants = new Dictionary <string, ConstantExpression>(context.AliasGlobalConstants); } // ADD global variables if (context.AliasGlobalVariables.Count > 0) { foreach (var keyValue in context.AliasGlobalVariables) { scope.CreateLazyVariable(keyValue.Key, new Lazy <Expression>(() => { var innerParameter = scope.CreateVariable(keyValue.Value.GetType(), keyValue.Key); var innerExpression = Expression.Assign(innerParameter, Expression.Constant(keyValue.Value)); scope.Expressions.Add(innerExpression); return(innerParameter); })); } } // CodeAnalysis var syntaxRoot = SyntaxParser.ParseText(code); // CodeCompiler var expression = ExpressionParser.ParseSyntax(scope, syntaxRoot, resultType); // Compile the expression var compiled = Expression.Lambda <TDelegate>(expression, parameterExpressions).Compile(); if (context.UseCache) { EvalManager.Cache.AddOrGetExisting(new CacheItem(cacheKey, compiled), new CacheItemPolicy()); } return(compiled); }
/// <summary>Compile the code or expression and return a TDelegate of type Func or Action to execute.</summary> /// <param name="context">The eval context used to compile the code or expression.</param> /// <param name="code">The code or expression to compile.</param> /// <param name="parameterTypes">The dictionary of parameter (name / type) used in the code or expression to compile.</param> /// <param name="resultType">Type of the compiled code or expression result.</param> /// <returns>A TDelegate of type Func or Action that represents the compiled code or expression.</returns> internal static EvalDelegate CompileSQLNET(EvalContext context, string code, IDictionary <string, Type> parameterTypes, Type resultType) { var cacheKey = ResolveCacheKey(context, typeof(Func <IDictionary, object>), code, parameterTypes); EvalDelegate cachedDelegate; if (EvalManager.CacheDelegate.TryGetValue(cacheKey, out cachedDelegate)) { return(cachedDelegate); } // Options var scope = new ExpressionScope { AliasExtensionMethods = context.AliasExtensionMethods, AliasNames = context.AliasNames, AliasStaticMembers = context.AliasStaticMembers, AliasTypes = context.AliasTypes, BindingFlags = context.BindingFlags, UseCaretForExponent = context.UseCaretForExponent }; // ADD global constants if (context.AliasGlobalConstants.Count > 0) { scope.Constants = new Dictionary <string, ConstantExpression>(context.AliasGlobalConstants); } // ADD global variables if (context.AliasGlobalVariables.Count > 0) { foreach (var keyValue in context.AliasGlobalVariables) { #if SQLNET scope.CreateLazyVariable(keyValue.Key, new LazySingleThread <Expression>(() => #else scope.CreateLazyVariable(keyValue.Key, new Lazy <Expression>(() => #endif { var innerParameter = scope.CreateVariable(keyValue.Value.GetType(), keyValue.Key); var innerExpression = Expression.Assign(innerParameter, Expression.Constant(keyValue.Value)); scope.Expressions.Add(innerExpression); return(innerParameter); })); } } // Resolve Parameter var parameterExpressions = ResolveParameter(scope, EvalCompilerParameterKind.Dictionary, parameterTypes); // CodeAnalysis var syntaxRoot = SyntaxParser.ParseText(code); // CodeCompiler var expression = ExpressionParser.ParseSyntax(scope, syntaxRoot, resultType); // Compile the expression var compiled = Expression.Lambda <Func <IDictionary, object> >(expression, parameterExpressions).Compile(); var evalDelegate = new EvalDelegate(cacheKey, compiled); EvalManager.CacheDelegate.TryAdd(cacheKey, evalDelegate); return(evalDelegate); }
/// <summary>Compile the code or expression and return a TDelegate of type Func or Action to execute.</summary> /// <param name="context">The eval context used to compile the code or expression.</param> /// <param name="code">The code or expression to compile.</param> /// <param name="parameterTypes">The dictionary of parameter (name / type) used in the code or expression to compile.</param> /// <param name="resultType">Type of the compiled code or expression result.</param> /// <returns>A TDelegate of type Func or Action that represents the compiled code or expression.</returns> internal static EvalDelegate Compile(EvalContext context, string code, ListDictionary parameterTypes, Type resultType) { var cacheKey = ResolveCacheKey(context, typeof (Func<IDictionary, object>), code, parameterTypes); EvalDelegate cachedDelegate; if (EvalManager.CacheDelegate.TryGetValue(cacheKey, out cachedDelegate)) { return cachedDelegate; } Dictionary<string, Type> parameterDict = new Dictionary<string, Type>(); foreach (DictionaryEntry parameterType in parameterTypes) { parameterDict.Add((string)parameterType.Key, (Type)parameterType.Value); } // Options var scope = new ExpressionScope { AliasExtensionMethods = context.AliasExtensionMethods, AliasNames = context.AliasNames, AliasStaticMembers = context.AliasStaticMembers, AliasTypes = context.AliasTypes, BindingFlags = context.BindingFlags, UseCaretForExponent = context.UseCaretForExponent }; // ADD global constants if (context.AliasGlobalConstants.Count > 0) { scope.Constants = new Dictionary<string, ConstantExpression>(context.AliasGlobalConstants); } // ADD global variables if (context.AliasGlobalVariables.Count > 0) { foreach (var keyValue in context.AliasGlobalVariables) { #if SQLNET scope.CreateLazyVariable(keyValue.Key, new LazySingleThread<Expression>(() => #else scope.CreateLazyVariable(keyValue.Key, new Lazy<Expression>(() => #endif { var innerParameter = scope.CreateVariable(keyValue.Value.GetType(), keyValue.Key); var innerExpression = Expression.Assign(innerParameter, Expression.Constant(keyValue.Value)); scope.Expressions.Add(innerExpression); return innerParameter; })); } } // Resolve Parameter var parameterExpressions = ResolveParameter(scope, parameterDict); // CodeAnalysis var syntaxRoot = SyntaxParser.ParseText(code); // CodeCompiler var expression = ExpressionParser.ParseSyntax(scope, syntaxRoot, resultType); // Compile the expression var compiled = Expression.Lambda<Func<IDictionary, object>>(expression, parameterExpressions).Compile(); var evalDelegate = new EvalDelegate(cacheKey, compiled); EvalManager.CacheDelegate.TryAdd(cacheKey, evalDelegate); return evalDelegate; }