Files
serein-flow/Serein.Script/SereinScriptInterpreter.cs

749 lines
29 KiB
C#
Raw Normal View History

using Newtonsoft.Json.Linq;
using Serein.Library;
using Serein.Library.Api;
using Serein.Library.Utils;
using Serein.Script.Node;
using System.ComponentModel.Design;
using System.Reflection;
using System.Reflection.Metadata.Ecma335;
using System.Runtime.CompilerServices;
using System.Xml.Linq;
namespace Serein.Script
{
public sealed class SereinSciptException : Exception
{
//public ASTNode Node { get; }
public override string Message { get; }
public SereinSciptException(ASTNode node, string message)
{
//this.Node = node;
Message = $"异常信息 : {message} ,代码在第{node.Row}行: {node.Code.Trim()}";
}
}
2024-12-21 20:47:31 +08:00
/// <summary>
/// 脚本运行上下文
/// </summary>
public interface IScriptInvokeContext
{
/// <summary>
/// 脚本运行的流程上下文,包含了流程上下文和变量等信息
/// </summary>
IDynamicContext FlowContext { get; }
/// <summary>
2024-12-21 20:47:31 +08:00
/// 是否该退出了
/// </summary>
2024-12-21 20:47:31 +08:00
bool IsReturn { get; }
/// <summary>
2024-12-21 20:47:31 +08:00
/// 是否严格检查 Null 值 (禁止使用 Null
/// </summary>
bool IsCheckNullValue { get; set; }
/// <summary>
2024-12-21 20:47:31 +08:00
/// 获取变量的值
/// </summary>
2024-12-21 20:47:31 +08:00
/// <param name="varName"></param>
/// <returns></returns>
object GetVarValue(string varName);
/// <summary>
2024-12-21 20:47:31 +08:00
/// 设置变量的值
/// </summary>
/// <param name="varName"></param>
/// <param name="value"></param>
/// <returns></returns>
bool SetVarValue(string varName, object value);
/// <summary>
/// 结束调用
/// </summary>
2024-12-21 20:47:31 +08:00
/// <returns></returns>
void OnExit();
2024-12-21 20:47:31 +08:00
}
2024-12-21 20:47:31 +08:00
public class ScriptInvokeContext : IScriptInvokeContext
{
public ScriptInvokeContext(IDynamicContext dynamicContext)
{
FlowContext = dynamicContext;
}
public IDynamicContext FlowContext{ get; }
/// <summary>
2024-12-21 20:47:31 +08:00
/// 定义的变量
/// </summary>
2024-12-21 20:47:31 +08:00
private Dictionary<string, object> _variables = new Dictionary<string, object>();
/// <summary>
/// 取消令牌源,用于控制脚本的执行
/// </summary>
private CancellationTokenSource _tokenSource = new CancellationTokenSource();
2024-12-21 20:47:31 +08:00
/// <summary>
/// 是否该退出了
/// </summary>
public bool IsReturn => _tokenSource.IsCancellationRequested;
2024-12-21 20:47:31 +08:00
/// <summary>
/// 是否严格检查 Null 值 (禁止使用 Null
/// </summary>
public bool IsCheckNullValue { get; set; }
2024-12-21 20:47:31 +08:00
object IScriptInvokeContext.GetVarValue(string varName)
{
_variables.TryGetValue(varName, out var value);
return value;
}
bool IScriptInvokeContext.SetVarValue(string varName, object? value)
{
2024-12-21 20:47:31 +08:00
if (!_variables.TryAdd(varName, value))
{
_variables[varName] = value;
}
return true;
}
void IScriptInvokeContext.OnExit()
2024-12-21 20:47:31 +08:00
{
// 清理脚本中加载的非托管资源
foreach (var nodeObj in _variables.Values)
{
if (nodeObj is not null)
{
if (typeof(IDisposable).IsAssignableFrom(nodeObj?.GetType()) && nodeObj is IDisposable disposable)
{
disposable?.Dispose();
}
}
else
{
}
}
_tokenSource.Cancel();
_variables.Clear();
}
2024-12-21 20:47:31 +08:00
}
/// <summary>
/// 脚本解释器,负责解析和执行 Serein 脚本
/// </summary>
2024-12-21 20:47:31 +08:00
public class SereinScriptInterpreter
{
/// <summary>
/// 挂载的函数
/// </summary>
private static Dictionary<string, DelegateDetails> _functionTable = new Dictionary<string, DelegateDetails>();
/// <summary>
/// 挂载的函数调用的对象(用于函数需要实例才能调用的场景)
/// </summary>
private Dictionary<string, Func<object>> _callFuncOfGetObjects = new Dictionary<string, Func<object>>();
/// <summary>
/// 定义的类型
/// </summary>
private Dictionary<string, Type> _classDefinition = new Dictionary<string, Type>();
/// <summary>
/// 挂载静态函数
/// </summary>
/// <param name="functionName"></param>
/// <param name="methodInfo"></param>
public static void AddStaticFunction(string functionName, MethodInfo methodInfo)
{
_functionTable[functionName] = new DelegateDetails(methodInfo);
}
/// <summary>
/// 挂载函数
/// </summary>
/// <param name="functionName">函数名称</param>
/// <param name="methodInfo">方法信息</param>
2024-12-21 20:47:31 +08:00
public void AddFunction(string functionName, MethodInfo methodInfo, Func<object>? callObj = null)
{
//if (!_functionTable.ContainsKey(functionName))
//{
// _functionTable[functionName] = new DelegateDetails(methodInfo);
//}
if(!methodInfo.IsStatic && callObj is null)
{
SereinEnv.WriteLine(InfoType.WARN, "函数挂载失败:试图挂载非静态的函数,但没有传入相应的获取实例的方法。");
return;
}
2024-12-21 20:47:31 +08:00
if(!methodInfo.IsStatic && callObj is not null && !_callFuncOfGetObjects.ContainsKey(functionName))
{
// 静态函数不需要
_callFuncOfGetObjects.Add(functionName, callObj);
}
2024-12-21 20:47:31 +08:00
if (!_functionTable.ContainsKey(functionName))
{
_functionTable[functionName] = new DelegateDetails(methodInfo);
}
//_functionTable[functionName] = new DelegateDetails(methodInfo);
}
/// <summary>
/// 挂载类型
/// </summary>
/// <param name="typeName">函数名称</param>
/// <param name="type">方法信息</param>
2024-12-21 20:47:31 +08:00
public void AddClassType(Type type , string typeName = "")
{
if (string.IsNullOrEmpty(typeName))
{
typeName = type.Name;
}
if (!_classDefinition.ContainsKey(typeName))
{
_classDefinition[typeName] = type;
}
}
/// <summary>
/// 入口节点
/// </summary>
/// <param name="programNode"></param>
/// <returns></returns>
2024-12-21 20:47:31 +08:00
private async Task<object?> ExecutionProgramNodeAsync(IScriptInvokeContext context, ProgramNode programNode)
{
2025-03-14 21:38:07 +08:00
// 加载变量
ASTNode statement = null;
try
{
// 遍历 ProgramNode 中的所有语句并执行它们
for (int index = 0; index < programNode.Statements.Count; index++)
{
statement = programNode.Statements[index];
// 直接退出
if (statement is ReturnNode returnNode) // 遇到 Return 语句 提前退出
{
return await EvaluateAsync(context, statement);
}
else
{
await InterpretAsync(context, statement);
}
}
return null;
}
catch (Exception ex )
{
if(statement is not null)
{
SereinEnv.WriteLine(InfoType.ERROR, $"脚本异常发生在[行{statement.Row}]{ex.Message}{Environment.NewLine}\t{statement.Code}");
}
throw;
}
}
/// <summary>
/// 类型定义
/// </summary>
/// <param name="programNode"></param>
/// <returns></returns>
private void ExecutionClassTypeDefinitionNode(ClassTypeDefinitionNode classTypeDefinitionNode)
{
2024-12-21 20:47:31 +08:00
if (_classDefinition.ContainsKey(classTypeDefinitionNode.ClassName) && !classTypeDefinitionNode.IsOverlay)
{
//SereinEnv.WriteLine(InfoType.WARN, $"异常信息 : 类型重复定义,代码在第{classTypeDefinitionNode.Row}行: {classTypeDefinitionNode.Code.Trim()}");
return;
}
2024-12-21 20:47:31 +08:00
var isOverlay = true; // classTypeDefinitionNode.IsOverlay;
var type = DynamicObjectHelper.CreateTypeWithProperties(classTypeDefinitionNode.Fields, classTypeDefinitionNode.ClassName, isOverlay); // 覆盖
classTypeDefinitionNode.IsOverlay = false; // 已经加载过,则不再覆盖
_classDefinition[classTypeDefinitionNode.ClassName] = type; // 定义对象
}
/// <summary>
/// IF...ELSE... 语句块
/// </summary>
/// <param name="ifNode"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
2024-12-21 20:47:31 +08:00
private async Task ExecutionIfNodeAsync(IScriptInvokeContext context, IfNode ifNode)
{
2024-12-21 20:47:31 +08:00
var result = await EvaluateAsync(context, ifNode.Condition) ?? throw new SereinSciptException(ifNode, $"条件语句返回了 null");
if (result is not bool condition)
{
throw new SereinSciptException(ifNode, "条件语句返回值不为 bool 类型");
}
if (condition)
{
foreach (var trueNode in ifNode.TrueBranch)
{
2024-12-21 20:47:31 +08:00
await InterpretAsync(context, trueNode);
}
}
else
{
foreach (var falseNode in ifNode.FalseBranch)
{
2024-12-21 20:47:31 +08:00
await InterpretAsync(context,falseNode);
}
}
}
/// <summary>
/// WHILE(){...} 语句块
/// </summary>
/// <param name="whileNode"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
2024-12-21 20:47:31 +08:00
private async Task ExectutionWhileNodeAsync(IScriptInvokeContext context, WhileNode whileNode)
{
while (true)
{
if (context.IsReturn) // 停止流程
{
return;
}
2024-12-21 20:47:31 +08:00
var result = await EvaluateAsync(context, whileNode.Condition) ?? throw new SereinSciptException(whileNode, $"条件语句返回了 null");
if (result is not bool condition)
{
throw new SereinSciptException(whileNode, $"条件语句返回值不为 bool 类型(当前返回值类型为 {result.GetType()})");
}
if (!condition)
{
break;
}
foreach(var node in whileNode.Body)
{
2024-12-21 20:47:31 +08:00
await InterpretAsync(context, node);
}
}
}
/// <summary>
/// 操作节点
/// </summary>
/// <param name="assignmentNode"></param>
/// <returns></returns>
2024-12-21 20:47:31 +08:00
private async Task ExecutionAssignmentNodeAsync(IScriptInvokeContext context, AssignmentNode assignmentNode)
{
2024-12-21 20:47:31 +08:00
var tmp = await EvaluateAsync(context, assignmentNode.Value);
if(tmp is not null)
{
context.SetVarValue(assignmentNode.Variable, tmp);
}
}
2024-12-21 20:47:31 +08:00
private async Task<object> InterpretFunctionCallAsync(IScriptInvokeContext context, FunctionCallNode functionCallNode)
{
if (functionCallNode.FunctionName.Equals("GetFlowContext", StringComparison.OrdinalIgnoreCase))
{
return context.FlowContext;
}
// 评估函数参数
var arguments = new object?[functionCallNode.Arguments.Count];
for (int i = 0; i < functionCallNode.Arguments.Count; i++)
{
ASTNode? arg = functionCallNode.Arguments[i];
2024-12-21 20:47:31 +08:00
arguments[i] = await EvaluateAsync(context, arg); // 评估每个参数
}
var funcName = functionCallNode.FunctionName;
object? instance = null; // 静态方法不需要传入实例所以可以传入null
// 查找并执行对应的函数
if (_functionTable.TryGetValue(funcName, out DelegateDetails? function))
{
if (!function.EmitMethodInfo.IsStatic)
{
if(_callFuncOfGetObjects.TryGetValue(funcName, out var action))
{
instance = action.Invoke();// 非静态的方法需要获取相应的实例
if (instance is null)
{
throw new SereinSciptException(functionCallNode, $"函数 {funcName} 尝试获取实例时返回了 null ");
}
}
else
{
throw new SereinSciptException(functionCallNode, $"挂载函数 {funcName} 时需要同时给定获取实例的 Func<object>");
}
}
var result = await function.InvokeAsync(instance,arguments);
return result;
}
else
{
throw new Exception($"Unknown function: {functionCallNode.FunctionName}");
}
}
/// <summary>
/// 解释操作
/// </summary>
/// <param name="context"></param>
/// <param name="node"></param>
/// <returns></returns>
/// <exception cref="SereinSciptException"></exception>
2024-12-21 20:47:31 +08:00
public async Task<object?> InterpretAsync(IScriptInvokeContext context, ASTNode node)
{
if(node == null)
{
return null;
}
switch (node)
{
case ProgramNode programNode: // AST树入口
2024-12-21 20:47:31 +08:00
var scritResult = await ExecutionProgramNodeAsync(context, programNode);
return scritResult; // 遍历 ProgramNode 中的所有语句并执行它们
case ClassTypeDefinitionNode classTypeDefinitionNode: // 定义类型
ExecutionClassTypeDefinitionNode(classTypeDefinitionNode);
break;
case AssignmentNode assignment: // 出现在 = 右侧的表达式
2024-12-21 20:47:31 +08:00
await ExecutionAssignmentNodeAsync(context, assignment);
break;
case MemberAssignmentNode memberAssignmentNode: // 设置对象属性
2024-12-21 20:47:31 +08:00
await SetMemberValue(context, memberAssignmentNode);
break;
case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用
2024-12-21 20:47:31 +08:00
return await CallMemberFunction(context, memberFunctionCallNode);
case IfNode ifNode: // 执行 if...else... 语句块
await ExecutionIfNodeAsync(context, ifNode);
break;
case WhileNode whileNode: // 循环语句块
2024-12-21 20:47:31 +08:00
await ExectutionWhileNodeAsync(context, whileNode);
break;
case FunctionCallNode functionCallNode: // 方法调用节点
2024-12-21 20:47:31 +08:00
return await InterpretFunctionCallAsync(context, functionCallNode);
case ReturnNode returnNode:
2024-12-21 20:47:31 +08:00
return await EvaluateAsync(context, returnNode);
default:
throw new SereinSciptException(node, "解释器 InterpretAsync() 未实现节点行为");
}
return null;
}
/// <summary>
/// 评估
/// </summary>
/// <param name="context"></param>
/// <param name="node"></param>
/// <returns></returns>
/// <exception cref="SereinSciptException"></exception>
2024-12-21 20:47:31 +08:00
private async Task<object?> EvaluateAsync(IScriptInvokeContext context, ASTNode node)
{
if(node == null)
{
return null;
}
switch (node)
{
case NullNode nullNode:
return null;
case BooleanNode booleanNode:
return booleanNode.Value; // 返回数值
case NumberIntNode numberNode:
return numberNode.Value; // 返回 int 整型数
case NumberLongNode numberNode:
return numberNode.Value; // 返回 long 整型数
case NumberFloatNode numberNode:
return numberNode.Value; // 返回 float 浮点型
case NumberDoubleNode numberNode:
return numberNode.Value; // 返回 double 浮点型
case StringNode stringNode:
return stringNode.Value; // 返回字符串值
case CharNode charNode:
return charNode.Value; // 返回Char
case IdentifierNode identifierNode:
2024-12-21 20:47:31 +08:00
return context.GetVarValue(identifierNode.Name);
//throw new SereinSciptException(identifierNode, "尝试使用值为null的变量");
//throw new SereinSciptException(identifierNode, "尝试使用未声明的变量");
case BinaryOperationNode binOpNode:
// 递归计算二元操作
2024-12-21 20:47:31 +08:00
var left = await EvaluateAsync(context, binOpNode.Left);
//if (left == null ) throw new SereinSciptException(binOpNode.Left, $"左值尝试使用 null");
2024-12-21 20:47:31 +08:00
var right = await EvaluateAsync(context, binOpNode.Right);
//if (right == null) throw new SereinSciptException(binOpNode.Right, "右值尝试使用计算 null");
return EvaluateBinaryOperation(left, binOpNode.Operator, right);
case ObjectInstantiationNode objectInstantiationNode: // 对象实例化
if (_classDefinition.TryGetValue(objectInstantiationNode.TypeName,out var type ))
{
object?[] args = new object[objectInstantiationNode.Arguments.Count];
for (int i = 0; i < objectInstantiationNode.Arguments.Count; i++)
{
var argNode = objectInstantiationNode.Arguments[i];
2024-12-21 20:47:31 +08:00
args[i] = await EvaluateAsync(context, argNode);
}
var obj = Activator.CreateInstance(type,args: args);// 创建对象
if (obj == null)
{
throw new SereinSciptException(objectInstantiationNode, $"类型创建失败\"{objectInstantiationNode.TypeName}\"");
}
return obj;
}
else
{
throw new SereinSciptException(objectInstantiationNode, $"使用了未定义的类型\"{objectInstantiationNode.TypeName}\"");
}
case FunctionCallNode callNode: // 调用方法
2024-12-21 20:47:31 +08:00
return await InterpretFunctionCallAsync(context, callNode); // 调用方法返回函数的返回值
case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用
2024-12-21 20:47:31 +08:00
return await CallMemberFunction(context, memberFunctionCallNode);
case MemberAccessNode memberAccessNode: // 对象成员访问
2024-12-21 20:47:31 +08:00
return await GetValue(context, memberAccessNode);
case CollectionIndexNode collectionIndexNode:
return await GetCollectionValue(context, collectionIndexNode);
case ReturnNode returnNode: // 返回内容
2024-12-21 20:47:31 +08:00
return await EvaluateAsync(context, returnNode.Value); // 直接返回响应的内容
//case ObjectInstantiationNode objectInstantiationNode: // 返回内容
default:
throw new SereinSciptException(node, $"解释器 EvaluateAsync() 未实现{node}节点行为");
}
}
private object EvaluateBinaryOperation(object left, string op, object right)
{
return BinaryOperationEvaluator.EvaluateValue(left, op, right);
// 根据运算符执行不同的运算
switch (op)
{
case "+":
if (left is string || right is string)
{
return left?.ToString() + right?.ToString(); // 字符串拼接
}
else if (left is int leftInt && right is int rightInt)
{
return leftInt + rightInt; // 整数加法
}
else if (left is long leftLong && right is long rightLong)
{
return leftLong + rightLong; // 整数加法
}
else if (left is double leftDouble && right is double rightDouble)
{
return leftDouble + rightDouble; // 整数加法
}
else
{
dynamic leftValue = Convert.ToDouble(left);
dynamic rightValue = Convert.ToDouble(right);
return leftValue + rightValue;
}
throw new Exception("Invalid types for + operator");
case "-":
return (int)left - (int)right;
case "*":
return (int)left * (int)right;
case "/":
return (int)left / (int)right;
case ">":
return (int)left > (int)right;
case "<":
return (int)left < (int)right;
case "==":
return Equals(left, right);
case "!=":
return !Equals(left, right);
default:
throw new NotImplementedException("未定义的操作符: " + op);
}
}
/// <summary>
/// 设置对象成员
/// </summary>
/// <param name="memberAssignmentNode"></param>
/// <returns></returns>
/// <exception cref="SereinSciptException"></exception>
2024-12-21 20:47:31 +08:00
public async Task SetMemberValue(IScriptInvokeContext context, MemberAssignmentNode memberAssignmentNode)
{
2024-12-21 20:47:31 +08:00
var target = await EvaluateAsync(context, memberAssignmentNode.Object);
var value = await EvaluateAsync(context, memberAssignmentNode.Value);
// 设置值
var lastMember = memberAssignmentNode.MemberName;
var lastProperty = target?.GetType().GetProperty(lastMember);
if (lastProperty is null)
{
var lastField = target?.GetType().GetRuntimeField(lastMember);
if (lastField is null)
{
throw new SereinSciptException(memberAssignmentNode, $"对象没有成员\"{memberAssignmentNode.MemberName}\"");
}
else
{
var convertedValue = Convert.ChangeType(value, lastField.FieldType);
lastField.SetValue(target, convertedValue);
}
}
else
{
var convertedValue = Convert.ChangeType(value, lastProperty.PropertyType);
lastProperty.SetValue(target, convertedValue);
}
}
/// <summary>
/// 获取对象成员
/// </summary>
/// <param name="memberAccessNode"></param>
/// <returns></returns>
/// <exception cref="SereinSciptException"></exception>
2024-12-21 20:47:31 +08:00
public async Task<object?> GetValue(IScriptInvokeContext context, MemberAccessNode memberAccessNode)
{
2024-12-21 20:47:31 +08:00
var target = await EvaluateAsync(context, memberAccessNode.Object);
var lastMember = memberAccessNode.MemberName;
var lastProperty = target?.GetType().GetProperty(lastMember);
if (lastProperty is null)
{
var lastField = target?.GetType().GetRuntimeField(lastMember);
if (lastField is null)
{
throw new SereinSciptException(memberAccessNode, $"对象没有成员\"{memberAccessNode.MemberName}\"");
}
else
{
return lastField.GetValue(target);
}
}
else
{
return lastProperty.GetValue(target);
}
}
/// <summary>
/// 获取集合中的成员
/// </summary>
/// <param name="memberAccessNode"></param>
/// <returns></returns>
/// <exception cref="SereinSciptException"></exception>
public async Task<object?> GetCollectionValue(IScriptInvokeContext context, CollectionIndexNode collectionIndexNode)
{
var target = await EvaluateAsync(context, collectionIndexNode.TargetValue); // 获取对象
if (target is null)
{
throw new ArgumentNullException($"解析{collectionIndexNode}节点时TargetValue返回空。");
}
// 解析数组/集合名与索引部分
var targetType = target.GetType(); // 目标对象的类型
#region
if (targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Dictionary<,>))
{
// 目标是键值对
var method = targetType.GetMethod("get_Item", BindingFlags.Public | BindingFlags.Instance);
if (method is not null)
{
var key = await EvaluateAsync(context, collectionIndexNode.IndexValue); // 获取索引值;
var result = method.Invoke(target, new object[] { key });
return result;
}
}
#endregion
#region
else
{
var indexValue = await EvaluateAsync(context, collectionIndexNode.IndexValue); // 获取索引值
object? result;
if (indexValue is int index)
{
// 获取数组或集合对象
// 访问数组或集合中的指定索引
if (target is Array array)
{
if (index < 0 || index >= array.Length)
{
throw new ArgumentException($"解析{collectionIndexNode}节点时,数组下标越界。");
}
result = array.GetValue(index);
return result;
}
else if (target is IList<object> list)
{
if (index < 0 || index >= list.Count)
{
throw new ArgumentException($"解析{collectionIndexNode}节点时,数组下标越界。");
}
result = list[index];
return result;
}
else
{
throw new ArgumentException($"解析{collectionIndexNode}节点时,左值并非有效集合。");
}
}
}
#endregion
throw new ArgumentException($"解析{collectionIndexNode}节点时,左值并非有效集合。");
}
/// <summary>
/// 缓存method委托
/// </summary>
private Dictionary<string, DelegateDetails> MethodToDelegateCaches { get; } = new Dictionary<string, DelegateDetails>();
2024-12-21 20:47:31 +08:00
public async Task<object?> CallMemberFunction(IScriptInvokeContext context, MemberFunctionCallNode memberFunctionCallNode)
{
2024-12-21 20:47:31 +08:00
var target = await EvaluateAsync(context, memberFunctionCallNode.Object);
var lastMember = memberFunctionCallNode.FunctionName;
var methodInfo = target?.GetType().GetMethod(lastMember) ?? throw new SereinSciptException(memberFunctionCallNode, $"对象没有方法\"{memberFunctionCallNode.FunctionName}\"");
if(!MethodToDelegateCaches.TryGetValue(methodInfo.Name, out DelegateDetails? delegateDetails))
{
delegateDetails = new DelegateDetails(methodInfo);
MethodToDelegateCaches[methodInfo.Name] = delegateDetails;
}
var arguments = new object?[memberFunctionCallNode.Arguments.Count];
for (int i = 0; i < memberFunctionCallNode.Arguments.Count; i++)
{
ASTNode? arg = memberFunctionCallNode.Arguments[i];
2024-12-21 20:47:31 +08:00
arguments[i] = await EvaluateAsync(context, arg); // 评估每个参数
}
return await delegateDetails.InvokeAsync(target, arguments);
}
}
}