using System; 
 | 
using System.Collections.Generic; 
 | 
using System.IO; 
 | 
using System.Linq; 
 | 
using System.Linq.Expressions; 
 | 
using System.Reflection; 
 | 
using System.Reflection.Emit; 
 | 
using System.Text; 
 | 
using Jace.Operations; 
 | 
  
 | 
namespace Jace.Util 
 | 
{ 
 | 
    /// <summary> 
 | 
    /// An adapter for creating a func wrapper around a func accepting a dictionary. The wrapper 
 | 
    /// can create a func that has an argument for every expected key in the dictionary. 
 | 
    /// </summary> 
 | 
    public class FuncAdapter 
 | 
    { 
 | 
        /// <summary> 
 | 
        /// Wrap the parsed the function into a delegate of the specified type. The delegate must accept  
 | 
        /// the parameters defined in the parameters collection. The order of parameters is respected as defined 
 | 
        /// in parameters collection. 
 | 
        /// <br/> 
 | 
        /// The function must accept a dictionary of strings and doubles as input. The values passed to the  
 | 
        /// wrapping function will be passed to the function using the dictionary. The keys in the dictionary 
 | 
        /// are the names of the parameters of the wrapping function. 
 | 
        /// </summary> 
 | 
        /// <param name="parameters">The required parameters of the wrapping function delegate.</param> 
 | 
        /// <param name="function">The function that must be wrapped.</param> 
 | 
        /// <returns>A delegate instance of the required type.</returns> 
 | 
        public Delegate Wrap(IEnumerable<Jace.Execution.ParameterInfo> parameters,  
 | 
            Func<IDictionary<string, double>, double> function) 
 | 
        { 
 | 
            Jace.Execution.ParameterInfo[] parameterArray = parameters.ToArray(); 
 | 
  
 | 
            return GenerateDelegate(parameterArray, function); 
 | 
        } 
 | 
  
 | 
        // Uncomment for debugging purposes 
 | 
        //public void CreateDynamicModuleBuilder() 
 | 
        //{ 
 | 
        //    AssemblyName assemblyName = new AssemblyName("JaceDynamicAssembly"); 
 | 
        //    AppDomain domain = AppDomain.CurrentDomain; 
 | 
        //    AssemblyBuilder assemblyBuilder = domain.DefineDynamicAssembly(assemblyName, 
 | 
        //        AssemblyBuilderAccess.RunAndSave); 
 | 
        //    ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name, "test.dll"); 
 | 
  
 | 
        //    TypeBuilder typeBuilder = moduleBuilder.DefineType("MyTestClass"); 
 | 
  
 | 
        //    MethodBuilder method = typeBuilder.DefineMethod("MyTestMethod", MethodAttributes.Static, typeof(double), 
 | 
        //       new Type[] { typeof(FuncAdapterArguments), typeof(int), typeof(double) }); 
 | 
  
 | 
        //    ILGenerator generator = method.GetILGenerator(); 
 | 
        //    GenerateMethodBody(generator, new List<Calculator.Execution.ParameterInfo>() {  
 | 
        //        new Calculator.Execution.ParameterInfo() { Name = "test1", DataType = DataType.Integer }, 
 | 
        //        new Calculator.Execution.ParameterInfo() { Name = "test2", DataType = DataType.FloatingPoint }}, 
 | 
        //        (a) => 0.0); 
 | 
  
 | 
        //    typeBuilder.CreateType(); 
 | 
  
 | 
        //    assemblyBuilder.Save(@"test.dll"); 
 | 
        //} 
 | 
  
 | 
        private Delegate GenerateDelegate(Jace.Execution.ParameterInfo[] parameterArray, 
 | 
            Func<Dictionary<string, double>, double> function) 
 | 
        { 
 | 
            Type delegateType = GetDelegateType(parameterArray); 
 | 
            Type dictionaryType = typeof(Dictionary<string, double>); 
 | 
  
 | 
            ParameterExpression dictionaryExpression = 
 | 
                Expression.Variable(typeof(Dictionary<string, double>), "dictionary"); 
 | 
            BinaryExpression dictionaryAssignExpression = 
 | 
                Expression.Assign(dictionaryExpression, Expression.New(dictionaryType)); 
 | 
  
 | 
            ParameterExpression[] parameterExpressions = new ParameterExpression[parameterArray.Length]; 
 | 
  
 | 
            List<Expression> methodBody = new List<Expression>(); 
 | 
            methodBody.Add(dictionaryAssignExpression); 
 | 
  
 | 
            for (int i = 0; i < parameterArray.Length; i++) 
 | 
            { 
 | 
                // Create parameter expression for each func parameter 
 | 
                Type parameterType = parameterArray[i].DataType == DataType.FloatingPoint ? typeof(double) : typeof(int); 
 | 
                parameterExpressions[i] = Expression.Parameter(parameterType, parameterArray[i].Name); 
 | 
  
 | 
                methodBody.Add(Expression.Call(dictionaryExpression, 
 | 
                    dictionaryType.GetRuntimeMethod("Add", new Type[] { typeof(string), typeof(double) }), 
 | 
                    Expression.Constant(parameterArray[i].Name), 
 | 
                    Expression.Convert(parameterExpressions[i], typeof(double))) 
 | 
                    ); 
 | 
            } 
 | 
  
 | 
            InvocationExpression invokeExpression = Expression.Invoke(Expression.Constant(function), dictionaryExpression); 
 | 
            methodBody.Add(invokeExpression); 
 | 
  
 | 
            LambdaExpression lambdaExpression = Expression.Lambda(delegateType, 
 | 
                Expression.Block(new[] { dictionaryExpression }, methodBody), 
 | 
                parameterExpressions); 
 | 
  
 | 
            return lambdaExpression.Compile(); 
 | 
        } 
 | 
  
 | 
        private Type GetDelegateType(Jace.Execution.ParameterInfo[] parameters) 
 | 
        { 
 | 
            string funcTypeName = string.Format("System.Func`{0}", parameters.Length + 1); 
 | 
            Type funcType = Type.GetType(funcTypeName); 
 | 
  
 | 
            Type[] typeArguments = new Type[parameters.Length + 1]; 
 | 
            for (int i = 0; i < parameters.Length; i++) 
 | 
                typeArguments[i] = (parameters[i].DataType == DataType.FloatingPoint) ? typeof(double) : typeof(int); 
 | 
            typeArguments[typeArguments.Length - 1] = typeof(double); 
 | 
  
 | 
            return funcType.MakeGenericType(typeArguments); 
 | 
        } 
 | 
  
 | 
        private class FuncAdapterArguments 
 | 
        { 
 | 
            private readonly Func<Dictionary<string, double>, double> function; 
 | 
  
 | 
            public FuncAdapterArguments(Func<Dictionary<string, double>, double> function) 
 | 
            { 
 | 
                this.function = function; 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
} 
 |