using Flee.PublicTypes; using System.Collections.Generic; namespace Convention.RScript { public static class ExpressionMath { public static int Sign(double value, double accuracy = ExpressionExtension.DefaultDoubleAccuracy) { if (value.IsCloseToZero(accuracy)) return 0; return value > 0 ? 1 : -1; } public static int Compare(double value1, double value2, double accuracy = ExpressionExtension.DefaultDoubleAccuracy) { if (value1.IsClose(value2, accuracy)) return 0; return value1 > value2 ? 1 : -1; } public static bool IsBetween(double value, double minValue, double maxValue, double accuracy = ExpressionExtension.DefaultDoubleAccuracy) { return Compare(value, minValue, accuracy) >= 0 && Compare(value, maxValue, accuracy) <= 0; } public static bool IsBetweenExclusive(double value, double minValue, double maxValue, double accuracy = ExpressionExtension.DefaultDoubleAccuracy) { return Compare(value, minValue, accuracy) > 0 && Compare(value, maxValue, accuracy) < 0; } public static int ToInt(double value) { return (int)value; } public static int ToInt(float value) { return (int)value; } public static int ToInt(int value) { return (int)value; } public static double ToDouble(float value) { return (double)value; } public static double ToDouble(int value) { return (double)value; } public static double ToDouble(double value) { return (double)value; } } public static class ExpressionExtension { public const double DefaultDoubleAccuracy = 1e-7; public static bool IsClose(this double value1, double value2, double maximumAbsoluteError = DefaultDoubleAccuracy) { if (double.IsInfinity(value1) || double.IsInfinity(value2)) { return Equals(value1, value2); } if (double.IsNaN(value1) || double.IsNaN(value2)) { return false; } var delta = value1 - value2; return !(delta > maximumAbsoluteError || delta < -maximumAbsoluteError); } public static bool IsCloseToZero(this double value, double maximumAbsoluteError = DefaultDoubleAccuracy) { return !(double.IsInfinity(value) || double.IsNaN(value) || value > maximumAbsoluteError || value < -maximumAbsoluteError); } } } namespace Convention.RScript.Parser { public class ExpressionParser { public readonly ExpressionContext context; public ExpressionParser(ExpressionContext context) { this.context = context; } private readonly Dictionary CompileGenericExpression = new(); private readonly Dictionary CompileDynamicExpression = new(); public void ClearCache() { CompileGenericExpression.Clear(); CompileDynamicExpression.Clear(); } public T Evaluate(string expression) { if (CompileGenericExpression.TryGetValue(expression, out var result)) { return (result as IGenericExpression).Evaluate(); } var compile = context.CompileGeneric(expression); CompileGenericExpression[expression] = compile; return compile.Evaluate(); } public object Evaluate(string expression) { if (CompileDynamicExpression.TryGetValue(expression, out var result)) { return result.Evaluate(); } var compile = context.CompileDynamic(expression); CompileDynamicExpression[expression] = compile; return compile.Evaluate(); } } }