/// <summary> /// Build a .NET func for the provided formula. /// </summary> /// <param name="formulaText">The formula that must be converted into a .NET func.</param> /// <param name="constants">Constant values for variables defined into the formula. They variables will be replaced by the constant value at pre-compilation time.</param> /// <returns>A .NET func for the provided formula.</returns> public Func <IDictionary <string, double>, double> Build(string formulaText, IDictionary <string, double> constants) { if (string.IsNullOrEmpty(formulaText)) { throw new ArgumentNullException("formulaText"); } ConstantRegistry compiledConstants = new ConstantRegistry(caseSensitive); if (constants != null) { foreach (var constant in constants) { compiledConstants.RegisterConstant(constant.Key, constant.Value); } } if (IsInFormulaCache(formulaText, compiledConstants, out var result)) { return(result); } else { Operation operation = BuildAbstractSyntaxTree(formulaText, compiledConstants); return(BuildFormula(formulaText, compiledConstants, operation)); } }
public void TestOverwritable() { ConstantRegistry registry = new ConstantRegistry(false); registry.RegisterConstant("test", 42.0); registry.RegisterConstant("test", 26.3); }
public void TestNotOverwritable() { ConstantRegistry registry = new ConstantRegistry(false); registry.RegisterConstant("test", 42.0, false); AssertExtensions.ThrowsException <Exception>(() => { registry.RegisterConstant("test", 26.3, false); }); }
public void TestAddConstant() { ConstantRegistry registry = new ConstantRegistry(false); registry.RegisterConstant("test", 42.0); ConstantInfo functionInfo = registry.GetConstantInfo("test"); Assert.IsNotNull(functionInfo); Assert.AreEqual("test", functionInfo.ConstantName); Assert.AreEqual(42.0, functionInfo.Value); }
/// <summary> /// Verify a collection of variables to ensure that all the variable names are valid. /// Users are not allowed to overwrite reserved variables or use function names as variables. /// If an invalid variable is detected an exception is thrown. /// </summary> /// <param name="variables">The colletion of variables that must be verified.</param> internal void VerifyVariableNames(IDictionary <string, ExecutionResult> variables) { foreach (string variableName in variables.Keys) { if (ConstantRegistry.IsConstantName(variableName) && !ConstantRegistry.GetConstantInfo(variableName).IsOverWritable) { throw new ArgumentException(string.Format("The name \"{0}\" is a reservered variable name that cannot be overwritten.", variableName), "variables"); } if (FunctionRegistry.IsFunctionName(variableName)) { throw new ArgumentException(string.Format("The name \"{0}\" is a function name. Parameters cannot have this name.", variableName), "variables"); } } }
/// <summary> /// Build the abstract syntax tree for a given formula. The formula string will /// be first tokenized. /// </summary> /// <param name="formulaText">A string containing the mathematical formula that must be converted /// into an abstract syntax tree.</param> /// <returns>The abstract syntax tree of the formula.</returns> private Operation BuildAbstractSyntaxTree(string formulaText, ConstantRegistry compiledConstants) { TokenReader tokenReader = new TokenReader(cultureInfo); List <Token> tokens = tokenReader.Read(formulaText); AstBuilder astBuilder = new AstBuilder(FunctionRegistry, caseSensitive, compiledConstants); Operation operation = astBuilder.Build(tokens); if (optimizerEnabled) { return(optimizer.Optimize(operation, this.FunctionRegistry, this.ConstantRegistry)); } else { return(operation); } }
private void RegisterDefaultConstants() { ConstantRegistry.RegisterConstant("e", Math.E, false); ConstantRegistry.RegisterConstant("pi", Math.PI, false); }
/// <summary> /// Removes a constant in the calculation engine. /// </summary> /// <param name="constantName">The name of the constant.</param> /// <param name="force">Can remove by force?(remove even nonWritable items)</param> public void RemoveConstant(string constantName, bool force = false) { ConstantRegistry.UnregisterConstant(constantName, force); }
/// <summary> /// Add a constant to the calculation engine. /// </summary> /// <param name="constantName">The name of the constant. This name can be used in mathematical formulas.</param> /// <param name="value">The value of the constant.</param> public void AddConstant(string constantName, ExecutionResult value) { ConstantRegistry.RegisterConstant(constantName, value); }
private string GenerateFormulaCacheKey(string formulaText, ConstantRegistry compiledConstants) { return((compiledConstants != null && compiledConstants.Any()) ? $"{formulaText}@{String.Join(",", compiledConstants?.Select(x => $"{x.ConstantName}:{x.Value}"))}" : formulaText); }
private bool IsInFormulaCache(string formulaText, ConstantRegistry compiledConstants, out Func <IDictionary <string, double>, double> function) { function = null; return(cacheEnabled && executionFormulaCache.TryGetValue(GenerateFormulaCacheKey(formulaText, compiledConstants), out function)); }
private Func <IDictionary <string, double>, double> BuildFormula(string formulaText, ConstantRegistry compiledConstants, Operation operation) { return(executionFormulaCache.GetOrAdd(GenerateFormulaCacheKey(formulaText, compiledConstants), v => executor.BuildFormula(operation, this.FunctionRegistry, this.ConstantRegistry))); }
/// <summary> /// Add a constant to the calculation engine. /// </summary> /// <param name="constantName">The name of the constant. This name can be used in mathematical formulas.</param> /// <param name="value">The value of the constant.</param> public void AddConstant(string constantName, double value) { ConstantRegistry.RegisterConstant(constantName, value); }