diff --git a/Math expression eval/UnitTest/TestAll.cs b/Math expression eval/UnitTest/TestAll.cs index 48fef10..a758747 100644 --- a/Math expression eval/UnitTest/TestAll.cs +++ b/Math expression eval/UnitTest/TestAll.cs @@ -1188,5 +1188,34 @@ public void Or_Operator_Test() .Bind("b", 1); Assert.AreEqual(true, expr4.Eval()); } + + + [TestMethod] + public void Custom_Function_Test() + { + //register new custom function + Parser.RegisterFunction("CUSTOM", typeof(customFunction)); + + //call function + var expr = new Expression("CUSTOM('1','a','#')"); + Assert.AreEqual("1-a-#", expr.Eval()); + } + + public class customFunction : org.matheval.Functions.IFunction + { + public List GetInfo() + { + return new List { new org.matheval.Functions.FunctionDef("custom", new Type[] { typeof(string), typeof(string), typeof(string) }, typeof(string), 3) }; + } + + public object Execute(Dictionary args, ExpressionContext dc) + { + string a1 = (string)args["1"]; + string a2 = (string)args["2"]; + string a3 = (string)args["3"]; + + return string.Join("-", a1, a2, a3); + } + } } } diff --git a/Math expression eval/org.matheval/Parser/Parser.cs b/Math expression eval/org.matheval/Parser/Parser.cs index d673c6a..c2da18a 100644 --- a/Math expression eval/org.matheval/Parser/Parser.cs +++ b/Math expression eval/org.matheval/Parser/Parser.cs @@ -36,6 +36,28 @@ namespace org.matheval { public class Parser { + private static Dictionary _registeredFunctions; + + /// + /// Registers a new custom function to all new Parsers + /// @param name function name as used in the expression + /// @param functionType type that implements the IFunction interface and will be used to handle the custom function call + /// + /// op + public static void RegisterFunction(string name, Type functionType) + { + if (_registeredFunctions == null) + { + _registeredFunctions = new Dictionary(); + } + //sanity check the provided type + //Additional checks could be done here to if needed. + if (functionType.IsAbstract || functionType.IsGenericType || !typeof(IFunction).IsAssignableFrom(functionType)) + throw new ArgumentException(functionType.Name + " is not a concrete, non-generic type that implements the org.matheval.Functions.IFunction interface"); + + _registeredFunctions[name.ToLowerInvariant()] = functionType; + } + /// /// Create object Lexer /// @@ -344,7 +366,10 @@ private Implements.Node ParseIdentifier() IFunction funcExecuter; try { - Type t = Type.GetType("org.matheval.Functions." + identifierStr.ToLowerInvariant() + "Function", true); + if (_registeredFunctions == null || !_registeredFunctions.TryGetValue(identifierStr.ToLowerInvariant(), out Type t)) + { + t = Type.GetType("org.matheval.Functions." + identifierStr.ToLowerInvariant() + "Function", true); + } Object obj = (Activator.CreateInstance(t)); if (obj == null)