Files
RScript/Parser/ExpressionParser.cs
2025-10-16 10:24:59 +08:00

130 lines
4.0 KiB
C#

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<string, IExpression> CompileGenericExpression = new();
private readonly Dictionary<string, IDynamicExpression> CompileDynamicExpression = new();
public void ClearCache()
{
CompileGenericExpression.Clear();
CompileDynamicExpression.Clear();
}
public T Evaluate<T>(string expression)
{
if (CompileGenericExpression.TryGetValue(expression, out var result))
{
return (result as IGenericExpression<T>).Evaluate();
}
var compile = context.CompileGeneric<T>(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();
}
}
}