199 lines
6.2 KiB
C#
199 lines
6.2 KiB
C#
using Flee.PublicTypes;
|
|
using System.Collections.Generic;
|
|
using System;
|
|
using System.Linq;
|
|
|
|
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, Type> CompileGenericExpressionTypen = new();
|
|
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();
|
|
}
|
|
return Compile<T>(expression).Evaluate();
|
|
}
|
|
|
|
public object Evaluate(string expression)
|
|
{
|
|
if (CompileDynamicExpression.TryGetValue(expression, out var result))
|
|
{
|
|
return result.Evaluate();
|
|
}
|
|
return Compile(expression).Evaluate();
|
|
}
|
|
|
|
public IGenericExpression<T> Compile<T>(string expression)
|
|
{
|
|
var compile = context.CompileGeneric<T>(expression);
|
|
CompileGenericExpression[expression] = compile;
|
|
CompileGenericExpressionTypen[expression] = typeof(T);
|
|
return compile;
|
|
}
|
|
|
|
public IDynamicExpression Compile(string expression)
|
|
{
|
|
var compile = context.CompileDynamic(expression);
|
|
CompileDynamicExpression[expression] = compile;
|
|
return compile;
|
|
}
|
|
|
|
[Serializable]
|
|
public struct SerializableParser
|
|
{
|
|
public Tuple<string, string>[] CompileGenericExpression;
|
|
public string[] CompileDynamicExpression;
|
|
}
|
|
|
|
public SerializableParser Serialize()
|
|
{
|
|
return new()
|
|
{
|
|
CompileGenericExpression = (from key in CompileGenericExpression.Keys select Tuple.Create(CompileGenericExpressionTypen[key].Name, key)).ToArray(),
|
|
CompileDynamicExpression = CompileDynamicExpression.Keys.ToArray()
|
|
};
|
|
}
|
|
|
|
public void Deserialize(SerializableParser data)
|
|
{
|
|
foreach (var (type, expr) in data.CompileGenericExpression)
|
|
{
|
|
if (type == nameof(String))
|
|
{
|
|
this.Compile<string>(expr);
|
|
}
|
|
else if (type == nameof(Single))
|
|
{
|
|
this.Compile<float>(expr);
|
|
}
|
|
else if (type == nameof(Double))
|
|
{
|
|
this.Compile<double>(expr);
|
|
}
|
|
else if (type == nameof(Int32))
|
|
{
|
|
this.Compile<int>(expr);
|
|
}
|
|
else if (type == nameof(Boolean))
|
|
{
|
|
this.Compile<bool>(expr);
|
|
}
|
|
else if (type == nameof(Object))
|
|
{
|
|
this.Compile<object>(expr);
|
|
}
|
|
else
|
|
{
|
|
throw new NotSupportedException($"Unsupported expression type: {type}");
|
|
}
|
|
}
|
|
foreach (var expr in data.CompileDynamicExpression)
|
|
{
|
|
this.Compile(expr);
|
|
}
|
|
}
|
|
}
|
|
}
|