/// <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 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 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 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 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 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;
        }
Пример #7
0
        /// <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 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);
                }
            }
        }
Пример #10
0
        /// <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);
        }
Пример #12
0
        /// <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);
        }
Пример #13
0
        /// <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);
        }
Пример #14
0
        /// <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;
        }