using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; using System.Collections; using Jace.Util; namespace Jace.Execution { public class FunctionRegistry : IFunctionRegistry { private const string DynamicFuncName = "Jace.DynamicFunc"; private readonly bool caseSensitive; private readonly Dictionary functions; public FunctionRegistry(bool caseSensitive) { this.caseSensitive = caseSensitive; this.functions = new Dictionary(); } public IEnumerator GetEnumerator() { return functions.Values.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } public FunctionInfo GetFunctionInfo(string functionName) { if (string.IsNullOrEmpty(functionName)) throw new ArgumentNullException("functionName"); FunctionInfo functionInfo = null; return functions.TryGetValue(ConvertFunctionName(functionName), out functionInfo) ? functionInfo : null; } public void RegisterFunction(string functionName, Delegate function) { RegisterFunction(functionName, function, true, true); } public void RegisterFunction(string functionName, Delegate function, bool isIdempotent, bool isOverWritable) { if (string.IsNullOrEmpty(functionName)) throw new ArgumentNullException("functionName"); if (function == null) throw new ArgumentNullException("function"); Type funcType = function.GetType(); bool isDynamicFunc = false; int numberOfParameters = -1; if (funcType.FullName.StartsWith("System.Func")) { foreach (Type genericArgument in funcType.GenericTypeArguments) if (genericArgument != typeof(double)) throw new ArgumentException("Only doubles are supported as function arguments.", "function"); numberOfParameters = function .GetMethodInfo() .GetParameters() .Count(p => p.ParameterType == typeof(double)); } else if (funcType.FullName.StartsWith(DynamicFuncName)) { isDynamicFunc = true; } else throw new ArgumentException("Only System.Func and " + DynamicFuncName + " delegates are permitted.", "function"); functionName = ConvertFunctionName(functionName); if (functions.ContainsKey(functionName) && !functions[functionName].IsOverWritable) { string message = string.Format("The function \"{0}\" cannot be overwriten.", functionName); throw new Exception(message); } if (functions.ContainsKey(functionName) && functions[functionName].NumberOfParameters != numberOfParameters) { string message = string.Format("The number of parameters cannot be changed when overwriting a method."); throw new Exception(message); } if (functions.ContainsKey(functionName) && functions[functionName].IsDynamicFunc != isDynamicFunc) { string message = string.Format("A Func can only be overwritten by another Func and a DynamicFunc can only be overwritten by another DynamicFunc."); throw new Exception(message); } FunctionInfo functionInfo = new FunctionInfo(functionName, numberOfParameters, isIdempotent, isOverWritable, isDynamicFunc, function); if (functions.ContainsKey(functionName)) functions[functionName] = functionInfo; else functions.Add(functionName, functionInfo); } public bool IsFunctionName(string functionName) { if (string.IsNullOrEmpty(functionName)) throw new ArgumentNullException("functionName"); return functions.ContainsKey(ConvertFunctionName(functionName)); } private string ConvertFunctionName(string functionName) { return caseSensitive ? functionName : functionName.ToLowerFast(); } } }