Files
RScript/Parser/ExpressionParser.cs
2025-11-26 17:58:30 +08:00

209 lines
6.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
// 默认启用未定义标识符作为字符串的功能
this.context.Options.UndefinedIdentifiersAsStrings = true;
// 启用大小写敏感
this.context.Options.CaseSensitive = true;
// 启用溢出检查
this.context.Options.Checked = true;
#if UNITY_EDITOR
// 浮点数使用float而非doubleUnity性能优化
this.context.Options.RealLiteralDataType = RealLiteralDataType.Single;
#endif
}
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);
}
}
}
}