mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-03 00:00:49 +08:00
修改了脚本执行的一些BUG。
This commit is contained in:
@@ -21,8 +21,45 @@ namespace Serein.Script
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 脚本运行上下文
|
||||
/// </summary>
|
||||
public interface IScriptInvokeContext
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否该退出了
|
||||
/// </summary>
|
||||
bool IsReturn { get; }
|
||||
|
||||
public class SereinScriptInterpreter
|
||||
/// <summary>
|
||||
/// 是否严格检查 Null 值 (禁止使用 Null)
|
||||
/// </summary>
|
||||
bool IsCheckNullValue { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取变量的值
|
||||
/// </summary>
|
||||
/// <param name="varName"></param>
|
||||
/// <returns></returns>
|
||||
object GetVarValue(string varName);
|
||||
|
||||
/// <summary>
|
||||
/// 设置变量的值
|
||||
/// </summary>
|
||||
/// <param name="varName"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
bool SetVarValue(string varName, object value);
|
||||
|
||||
/// <summary>
|
||||
/// 结束调用
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
bool Exit();
|
||||
}
|
||||
|
||||
|
||||
public class ScriptInvokeContext : IScriptInvokeContext
|
||||
{
|
||||
/// <summary>
|
||||
/// 定义的变量
|
||||
@@ -30,25 +67,37 @@ namespace Serein.Script
|
||||
private Dictionary<string, object> _variables = new Dictionary<string, object>();
|
||||
|
||||
/// <summary>
|
||||
/// 挂载的函数
|
||||
/// 是否该退出了
|
||||
/// </summary>
|
||||
private static Dictionary<string, DelegateDetails> _functionTable = new Dictionary<string, DelegateDetails>();
|
||||
public bool IsReturn { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 挂载的函数调用的对象(用于函数需要实例才能调用的场景)
|
||||
/// 是否严格检查 Null 值 (禁止使用 Null)
|
||||
/// </summary>
|
||||
private static Dictionary<string, Func<object>> _callFuncOfGetObjects = new Dictionary<string, Func<object>>();
|
||||
public bool IsCheckNullValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 定义的类型
|
||||
/// </summary>
|
||||
private static Dictionary<string, Type> _classDefinition = new Dictionary<string, Type>();
|
||||
|
||||
/// <summary>
|
||||
/// 重置的变量
|
||||
/// </summary>
|
||||
public void ResetVar()
|
||||
object IScriptInvokeContext.GetVarValue(string varName)
|
||||
{
|
||||
_variables.TryGetValue(varName, out var value);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
bool IScriptInvokeContext.SetVarValue(string varName, object? value)
|
||||
{
|
||||
if (!_variables.TryAdd(varName, value))
|
||||
{
|
||||
_variables[varName] = value;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool IScriptInvokeContext.Exit()
|
||||
{
|
||||
// 清理脚本中加载的非托管资源
|
||||
foreach (var nodeObj in _variables.Values)
|
||||
{
|
||||
if (nodeObj is not null)
|
||||
@@ -64,14 +113,47 @@ namespace Serein.Script
|
||||
}
|
||||
}
|
||||
_variables.Clear();
|
||||
return true ;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
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>
|
||||
public static void AddFunction(string functionName, MethodInfo methodInfo, Func<object>? callObj = null)
|
||||
public void AddFunction(string functionName, MethodInfo methodInfo, Func<object>? callObj = null)
|
||||
{
|
||||
//if (!_functionTable.ContainsKey(functionName))
|
||||
//{
|
||||
@@ -84,12 +166,16 @@ namespace Serein.Script
|
||||
}
|
||||
|
||||
|
||||
if(!methodInfo.IsStatic && callObj is not null)
|
||||
if(!methodInfo.IsStatic && callObj is not null && !_callFuncOfGetObjects.ContainsKey(functionName))
|
||||
{
|
||||
// 静态函数不需要
|
||||
_callFuncOfGetObjects.Add(functionName, callObj);
|
||||
}
|
||||
_functionTable[functionName] = new DelegateDetails(methodInfo);
|
||||
if (!_functionTable.ContainsKey(functionName))
|
||||
{
|
||||
_functionTable[functionName] = new DelegateDetails(methodInfo);
|
||||
}
|
||||
//_functionTable[functionName] = new DelegateDetails(methodInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -97,7 +183,7 @@ namespace Serein.Script
|
||||
/// </summary>
|
||||
/// <param name="typeName">函数名称</param>
|
||||
/// <param name="type">方法信息</param>
|
||||
public static void AddClassType(Type type , string typeName = "")
|
||||
public void AddClassType(Type type , string typeName = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(typeName))
|
||||
{
|
||||
@@ -115,7 +201,7 @@ namespace Serein.Script
|
||||
/// </summary>
|
||||
/// <param name="programNode"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<object?> ExecutionProgramNodeAsync(ProgramNode programNode)
|
||||
private async Task<object?> ExecutionProgramNodeAsync(IScriptInvokeContext context, ProgramNode programNode)
|
||||
{
|
||||
// 遍历 ProgramNode 中的所有语句并执行它们
|
||||
foreach (var statement in programNode.Statements)
|
||||
@@ -123,11 +209,11 @@ namespace Serein.Script
|
||||
// 直接退出
|
||||
if (statement is ReturnNode returnNode) // 遇到 Return 语句 提前退出
|
||||
{
|
||||
return await EvaluateAsync(statement);
|
||||
return await EvaluateAsync(context, statement);
|
||||
}
|
||||
else
|
||||
{
|
||||
await InterpretAsync(statement);
|
||||
await InterpretAsync(context, statement);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,12 +227,16 @@ namespace Serein.Script
|
||||
/// <returns></returns>
|
||||
private void ExecutionClassTypeDefinitionNode(ClassTypeDefinitionNode classTypeDefinitionNode)
|
||||
{
|
||||
if (_classDefinition.ContainsKey(classTypeDefinitionNode.ClassName))
|
||||
if (_classDefinition.ContainsKey(classTypeDefinitionNode.ClassName) && !classTypeDefinitionNode.IsOverlay)
|
||||
{
|
||||
//SereinEnv.WriteLine(InfoType.WARN, $"异常信息 : 类型重复定义,代码在第{classTypeDefinitionNode.Row}行: {classTypeDefinitionNode.Code.Trim()}");
|
||||
return;
|
||||
}
|
||||
var type = DynamicObjectHelper.CreateTypeWithProperties(classTypeDefinitionNode.Fields, classTypeDefinitionNode.ClassName);
|
||||
|
||||
var isOverlay = true; // classTypeDefinitionNode.IsOverlay;
|
||||
|
||||
var type = DynamicObjectHelper.CreateTypeWithProperties(classTypeDefinitionNode.Fields, classTypeDefinitionNode.ClassName, isOverlay); // 覆盖
|
||||
classTypeDefinitionNode.IsOverlay = false; // 已经加载过,则不再覆盖
|
||||
_classDefinition[classTypeDefinitionNode.ClassName] = type; // 定义对象
|
||||
}
|
||||
|
||||
@@ -156,9 +246,9 @@ namespace Serein.Script
|
||||
/// <param name="ifNode"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
private async Task ExecutionIfNodeAsync(IfNode ifNode)
|
||||
private async Task ExecutionIfNodeAsync(IScriptInvokeContext context, IfNode ifNode)
|
||||
{
|
||||
var result = await EvaluateAsync(ifNode.Condition) ?? throw new SereinSciptException(ifNode, $"条件语句返回了 null");
|
||||
var result = await EvaluateAsync(context, ifNode.Condition) ?? throw new SereinSciptException(ifNode, $"条件语句返回了 null");
|
||||
|
||||
if (result is not bool condition)
|
||||
{
|
||||
@@ -169,14 +259,14 @@ namespace Serein.Script
|
||||
{
|
||||
foreach (var trueNode in ifNode.TrueBranch)
|
||||
{
|
||||
await InterpretAsync(trueNode);
|
||||
await InterpretAsync(context, trueNode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var falseNode in ifNode.FalseBranch)
|
||||
{
|
||||
await InterpretAsync(falseNode);
|
||||
await InterpretAsync(context,falseNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -187,11 +277,11 @@ namespace Serein.Script
|
||||
/// <param name="whileNode"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
private async Task ExectutionWhileNodeAsync(WhileNode whileNode)
|
||||
private async Task ExectutionWhileNodeAsync(IScriptInvokeContext context, WhileNode whileNode)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var result = await EvaluateAsync(whileNode.Condition) ?? throw new SereinSciptException(whileNode, $"条件语句返回了 null");
|
||||
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()})");
|
||||
@@ -202,7 +292,7 @@ namespace Serein.Script
|
||||
}
|
||||
foreach(var node in whileNode.Body)
|
||||
{
|
||||
await InterpretAsync(node);
|
||||
await InterpretAsync(context, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -212,19 +302,19 @@ namespace Serein.Script
|
||||
/// </summary>
|
||||
/// <param name="assignmentNode"></param>
|
||||
/// <returns></returns>
|
||||
private async Task ExecutionAssignmentNodeAsync(AssignmentNode assignmentNode)
|
||||
private async Task ExecutionAssignmentNodeAsync(IScriptInvokeContext context, AssignmentNode assignmentNode)
|
||||
{
|
||||
var tmp = await EvaluateAsync(assignmentNode.Value);
|
||||
_variables[assignmentNode.Variable] = tmp;
|
||||
var tmp = await EvaluateAsync(context, assignmentNode.Value);
|
||||
context.SetVarValue(assignmentNode.Variable, tmp);
|
||||
}
|
||||
private async Task<object> InterpretFunctionCallAsync(FunctionCallNode functionCallNode)
|
||||
private async Task<object> InterpretFunctionCallAsync(IScriptInvokeContext context, FunctionCallNode functionCallNode)
|
||||
{
|
||||
// 评估函数参数
|
||||
var arguments = new object?[functionCallNode.Arguments.Count];
|
||||
for (int i = 0; i < functionCallNode.Arguments.Count; i++)
|
||||
{
|
||||
ASTNode? arg = functionCallNode.Arguments[i];
|
||||
arguments[i] = await EvaluateAsync(arg); // 评估每个参数
|
||||
arguments[i] = await EvaluateAsync(context, arg); // 评估每个参数
|
||||
}
|
||||
|
||||
var funcName = functionCallNode.FunctionName;
|
||||
@@ -263,7 +353,7 @@ namespace Serein.Script
|
||||
|
||||
|
||||
|
||||
public async Task<object?> InterpretAsync(ASTNode node)
|
||||
public async Task<object?> InterpretAsync(IScriptInvokeContext context, ASTNode node)
|
||||
{
|
||||
if(node == null)
|
||||
{
|
||||
@@ -273,30 +363,29 @@ namespace Serein.Script
|
||||
switch (node)
|
||||
{
|
||||
case ProgramNode programNode: // AST树入口
|
||||
var scritResult = await ExecutionProgramNodeAsync(programNode);
|
||||
var scritResult = await ExecutionProgramNodeAsync(context, programNode);
|
||||
return scritResult; // 遍历 ProgramNode 中的所有语句并执行它们
|
||||
case ClassTypeDefinitionNode classTypeDefinitionNode: // 定义类型
|
||||
ExecutionClassTypeDefinitionNode(classTypeDefinitionNode);
|
||||
break;
|
||||
case AssignmentNode assignment: // 出现在 = 右侧的表达式
|
||||
await ExecutionAssignmentNodeAsync(assignment);
|
||||
await ExecutionAssignmentNodeAsync(context, assignment);
|
||||
break;
|
||||
case MemberAssignmentNode memberAssignmentNode: // 设置对象属性
|
||||
await SetMemberValue(memberAssignmentNode);
|
||||
await SetMemberValue(context, memberAssignmentNode);
|
||||
break;
|
||||
case MemberFunctionCallNode memberFunctionCallNode:
|
||||
return await CallMemberFunction(memberFunctionCallNode);
|
||||
break;
|
||||
return await CallMemberFunction(context, memberFunctionCallNode);
|
||||
case IfNode ifNode: // 执行 if...else... 语句块
|
||||
await ExecutionIfNodeAsync(ifNode);
|
||||
await ExecutionIfNodeAsync(context, ifNode);
|
||||
break;
|
||||
case WhileNode whileNode: // 循环语句块
|
||||
await ExectutionWhileNodeAsync(whileNode);
|
||||
await ExectutionWhileNodeAsync(context, whileNode);
|
||||
break;
|
||||
case FunctionCallNode functionCallNode: // 方法调用节点
|
||||
return await InterpretFunctionCallAsync(functionCallNode);
|
||||
return await InterpretFunctionCallAsync(context, functionCallNode);
|
||||
case ReturnNode returnNode:
|
||||
return await EvaluateAsync(returnNode);
|
||||
return await EvaluateAsync(context, returnNode);
|
||||
default:
|
||||
throw new SereinSciptException(node, "解释器 InterpretAsync() 未实现节点行为");
|
||||
}
|
||||
@@ -304,7 +393,7 @@ namespace Serein.Script
|
||||
}
|
||||
|
||||
|
||||
private async Task<object?> EvaluateAsync(ASTNode node)
|
||||
private async Task<object?> EvaluateAsync(IScriptInvokeContext context, ASTNode node)
|
||||
{
|
||||
if(node == null)
|
||||
{
|
||||
@@ -321,27 +410,17 @@ namespace Serein.Script
|
||||
case StringNode stringNode:
|
||||
return stringNode.Value; // 返回字符串值
|
||||
case IdentifierNode identifierNode:
|
||||
if (_variables.TryGetValue(identifierNode.Name, out var result))
|
||||
{
|
||||
//if(result == null)
|
||||
//{
|
||||
// throw new SereinSciptException(identifierNode, "尝试使用值为null的变量");
|
||||
//}
|
||||
return result; // 获取变量值
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new SereinSciptException(identifierNode, "尝试使用未声明的变量");
|
||||
}
|
||||
return context.GetVarValue(identifierNode.Name);
|
||||
//throw new SereinSciptException(identifierNode, "尝试使用值为null的变量");
|
||||
//throw new SereinSciptException(identifierNode, "尝试使用未声明的变量");
|
||||
case BinaryOperationNode binOpNode:
|
||||
// 递归计算二元操作
|
||||
var left = await EvaluateAsync(binOpNode.Left);
|
||||
var left = await EvaluateAsync(context, binOpNode.Left);
|
||||
//if (left == null )
|
||||
//{
|
||||
// throw new SereinSciptException(binOpNode.Left, $"左值尝试使用 null");
|
||||
//}
|
||||
|
||||
var right = await EvaluateAsync(binOpNode.Right);
|
||||
var right = await EvaluateAsync(context, binOpNode.Right);
|
||||
//if (right == null)
|
||||
//{
|
||||
// throw new SereinSciptException(binOpNode.Right, "右值尝试使用计算 null");
|
||||
@@ -354,7 +433,7 @@ namespace Serein.Script
|
||||
for (int i = 0; i < objectInstantiationNode.Arguments.Count; i++)
|
||||
{
|
||||
var argNode = objectInstantiationNode.Arguments[i];
|
||||
args[i] = await EvaluateAsync(argNode);
|
||||
args[i] = await EvaluateAsync(context, argNode);
|
||||
}
|
||||
var obj = Activator.CreateInstance(type,args: args);// 创建对象
|
||||
if (obj == null)
|
||||
@@ -370,11 +449,13 @@ namespace Serein.Script
|
||||
|
||||
}
|
||||
case FunctionCallNode callNode:
|
||||
return await InterpretFunctionCallAsync(callNode); // 调用方法返回函数的返回值
|
||||
return await InterpretFunctionCallAsync(context, callNode); // 调用方法返回函数的返回值
|
||||
case MemberFunctionCallNode memberFunctionCallNode:
|
||||
return await CallMemberFunction(context, memberFunctionCallNode);
|
||||
case MemberAccessNode memberAccessNode:
|
||||
return await GetValue(memberAccessNode);
|
||||
return await GetValue(context, memberAccessNode);
|
||||
case ReturnNode returnNode: //
|
||||
return await EvaluateAsync(returnNode.Value); // 直接返回响应的内容
|
||||
return await EvaluateAsync(context, returnNode.Value); // 直接返回响应的内容
|
||||
default:
|
||||
throw new SereinSciptException(node, "解释器 EvaluateAsync() 未实现节点行为");
|
||||
}
|
||||
@@ -440,10 +521,10 @@ namespace Serein.Script
|
||||
/// <param name="memberAssignmentNode"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="SereinSciptException"></exception>
|
||||
public async Task SetMemberValue(MemberAssignmentNode memberAssignmentNode)
|
||||
public async Task SetMemberValue(IScriptInvokeContext context, MemberAssignmentNode memberAssignmentNode)
|
||||
{
|
||||
var target = await EvaluateAsync(memberAssignmentNode.Object);
|
||||
var value = await EvaluateAsync(memberAssignmentNode.Value);
|
||||
var target = await EvaluateAsync(context, memberAssignmentNode.Object);
|
||||
var value = await EvaluateAsync(context, memberAssignmentNode.Value);
|
||||
// 设置值
|
||||
var lastMember = memberAssignmentNode.MemberName;
|
||||
|
||||
@@ -474,9 +555,9 @@ namespace Serein.Script
|
||||
/// <param name="memberAccessNode"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="SereinSciptException"></exception>
|
||||
public async Task<object?> GetValue(MemberAccessNode memberAccessNode)
|
||||
public async Task<object?> GetValue(IScriptInvokeContext context, MemberAccessNode memberAccessNode)
|
||||
{
|
||||
var target = await EvaluateAsync(memberAccessNode.Object);
|
||||
var target = await EvaluateAsync(context, memberAccessNode.Object);
|
||||
var lastMember = memberAccessNode.MemberName;
|
||||
|
||||
var lastProperty = target?.GetType().GetProperty(lastMember);
|
||||
@@ -503,9 +584,9 @@ namespace Serein.Script
|
||||
/// </summary>
|
||||
private Dictionary<string, DelegateDetails> MethodToDelegateCaches { get; } = new Dictionary<string, DelegateDetails>();
|
||||
|
||||
public async Task<object?> CallMemberFunction(MemberFunctionCallNode memberFunctionCallNode)
|
||||
public async Task<object?> CallMemberFunction(IScriptInvokeContext context, MemberFunctionCallNode memberFunctionCallNode)
|
||||
{
|
||||
var target = await EvaluateAsync(memberFunctionCallNode.Object);
|
||||
var target = await EvaluateAsync(context, memberFunctionCallNode.Object);
|
||||
var lastMember = memberFunctionCallNode.FunctionName;
|
||||
|
||||
var methodInfo = target?.GetType().GetMethod(lastMember) ?? throw new SereinSciptException(memberFunctionCallNode, $"对象没有方法\"{memberFunctionCallNode.FunctionName}\"");
|
||||
@@ -521,7 +602,7 @@ namespace Serein.Script
|
||||
for (int i = 0; i < memberFunctionCallNode.Arguments.Count; i++)
|
||||
{
|
||||
ASTNode? arg = memberFunctionCallNode.Arguments[i];
|
||||
arguments[i] = await EvaluateAsync(arg); // 评估每个参数
|
||||
arguments[i] = await EvaluateAsync(context, arg); // 评估每个参数
|
||||
}
|
||||
|
||||
return await delegateDetails.InvokeAsync(target, arguments);
|
||||
|
||||
Reference in New Issue
Block a user