diff --git a/Library/FlowNode/NodeModelBaseFunc.cs b/Library/FlowNode/NodeModelBaseFunc.cs index d0a5a05..e7a8020 100644 --- a/Library/FlowNode/NodeModelBaseFunc.cs +++ b/Library/FlowNode/NodeModelBaseFunc.cs @@ -102,6 +102,7 @@ namespace Serein.Library { return new ParameterData[0]; } + if (MethodDetails.ParameterDetailss.Length > 0) { return MethodDetails.ParameterDetailss @@ -182,8 +183,7 @@ namespace Serein.Library { md.ParameterDetailss = new ParameterDetails[0]; } - LoadCustomData(nodeInfo); // 加载自定义数据 - + var pds = md.ParameterDetailss; // 当前节点的入参描述数组 #region 类库方法型节点加载参数 if (nodeInfo.ParameterData.Length > pds.Length && md.HasParamsArg) @@ -215,7 +215,10 @@ namespace Serein.Library pd.ArgDataSourceType = EnumHelper.ConvertEnum(pdInfo.SourceType); pd.ArgDataSourceNodeGuid = pdInfo.SourceNodeGuid; - } + } + + LoadCustomData(nodeInfo); // 加载自定义数据 + #endregion } } diff --git a/NodeFlow/Model/SingleScriptNode.cs b/NodeFlow/Model/SingleScriptNode.cs index 4152264..38b72a2 100644 --- a/NodeFlow/Model/SingleScriptNode.cs +++ b/NodeFlow/Model/SingleScriptNode.cs @@ -143,14 +143,14 @@ namespace Serein.NodeFlow.Model varNames.Add(pd.Name); } - //StringBuilder sb = new StringBuilder(); - //foreach (var pd in MethodDetails.ParameterDetailss) - //{ - // sb.AppendLine($"let {pd.Name};"); // 提前声明这些变量 - //} - //sb.Append(Script); - //var p = new SereinScriptParser(sb.ToString()); - var p = new SereinScriptParser(Script); + StringBuilder sb = new StringBuilder(); + foreach (var pd in MethodDetails.ParameterDetailss) + { + sb.AppendLine($"let {pd.Name};"); // 提前声明这些变量 + } + sb.Append(Script); + var p = new SereinScriptParser(sb.ToString()); + //var p = new SereinScriptParser(Script); mainNode = p.Parse(); // 开始解析 } catch (Exception ex) @@ -168,6 +168,7 @@ namespace Serein.NodeFlow.Model public override async Task ExecutingAsync(IDynamicContext context) { var @params = await GetParametersAsync(context); + //context.AddOrUpdate($"{context.Guid}_{this.Guid}_Params", @params[0]); // 后面再改 ReloadScript();// 每次都重新解析 @@ -183,9 +184,17 @@ namespace Serein.NodeFlow.Model scriptContext.SetVarValue(argName, argData); } } - + + FlowRunCompleteHandler onFlowStop = (e) => + { + scriptContext.OnExit(); + }; + + var envEvent = (IFlowEnvironmentEvent)context.Env; + envEvent.OnFlowRunComplete += onFlowStop; // 防止运行后台流程 var result = await ScriptInterpreter.InterpretAsync(scriptContext, mainNode); // 从入口节点执行 + envEvent.OnFlowRunComplete -= onFlowStop; //SereinEnv.WriteLine(InfoType.INFO, "FlowContext Guid : " + context.Guid); return result; } @@ -237,7 +246,6 @@ namespace Serein.NodeFlow.Model } else if (value is TimeSpan timeSpan) { - Console.WriteLine($"等待{timeSpan}"); await Task.Delay(timeSpan); } diff --git a/Serein.Script/Node/CollectionIndexNode.cs b/Serein.Script/Node/CollectionIndexNode.cs index 5f7a592..124e032 100644 --- a/Serein.Script/Node/CollectionIndexNode.cs +++ b/Serein.Script/Node/CollectionIndexNode.cs @@ -11,9 +11,11 @@ namespace Serein.Script.Node /// public class CollectionIndexNode : ASTNode { + public ASTNode TargetValue { get; } public ASTNode IndexValue { get; } - public CollectionIndexNode(ASTNode indexValue) + public CollectionIndexNode(ASTNode collectionValue,ASTNode indexValue) { + this.TargetValue = collectionValue; this.IndexValue = indexValue; } } diff --git a/Serein.Script/SereinScriptInterpreter.cs b/Serein.Script/SereinScriptInterpreter.cs index 9bb68a0..dfefd74 100644 --- a/Serein.Script/SereinScriptInterpreter.cs +++ b/Serein.Script/SereinScriptInterpreter.cs @@ -3,7 +3,9 @@ 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; @@ -21,12 +23,15 @@ namespace Serein.Script } } + + /// /// 脚本运行上下文 /// public interface IScriptInvokeContext { IDynamicContext FlowContext { get; } + /// /// 是否该退出了 /// @@ -35,7 +40,7 @@ namespace Serein.Script /// /// 是否严格检查 Null 值 (禁止使用 Null) /// - bool IsCheckNullValue { get; } + bool IsCheckNullValue { get; set; } /// /// 获取变量的值 @@ -56,7 +61,7 @@ namespace Serein.Script /// 结束调用 /// /// - bool Exit(); + void OnExit(); } @@ -73,11 +78,13 @@ namespace Serein.Script /// 定义的变量 /// private Dictionary _variables = new Dictionary(); + + private CancellationTokenSource _tokenSource = new CancellationTokenSource(); /// /// 是否该退出了 /// - public bool IsReturn { get; set; } + public bool IsReturn => _tokenSource.IsCancellationRequested; /// /// 是否严格检查 Null 值 (禁止使用 Null) @@ -104,7 +111,7 @@ namespace Serein.Script - bool IScriptInvokeContext.Exit() + void IScriptInvokeContext.OnExit() { // 清理脚本中加载的非托管资源 foreach (var nodeObj in _variables.Values) @@ -121,8 +128,8 @@ namespace Serein.Script } } + _tokenSource.Cancel(); _variables.Clear(); - return true ; } } @@ -213,6 +220,7 @@ namespace Serein.Script private async Task ExecutionProgramNodeAsync(IScriptInvokeContext context, ProgramNode programNode) { // 加载变量 + // 遍历 ProgramNode 中的所有语句并执行它们 foreach (var statement in programNode.Statements) @@ -290,8 +298,13 @@ namespace Serein.Script /// private async Task ExectutionWhileNodeAsync(IScriptInvokeContext context, WhileNode whileNode) { + while (true) { + if (context.IsReturn) // 停止流程 + { + return; + } var result = await EvaluateAsync(context, whileNode.Condition) ?? throw new SereinSciptException(whileNode, $"条件语句返回了 null"); if (result is not bool condition) { @@ -316,7 +329,11 @@ namespace Serein.Script private async Task ExecutionAssignmentNodeAsync(IScriptInvokeContext context, AssignmentNode assignmentNode) { var tmp = await EvaluateAsync(context, assignmentNode.Value); - context.SetVarValue(assignmentNode.Variable, tmp); + if(tmp is not null) + { + context.SetVarValue(assignmentNode.Variable, tmp); + + } } private async Task InterpretFunctionCallAsync(IScriptInvokeContext context, FunctionCallNode functionCallNode) { @@ -378,6 +395,7 @@ namespace Serein.Script switch (node) { case ProgramNode programNode: // AST树入口 + var scritResult = await ExecutionProgramNodeAsync(context, programNode); return scritResult; // 遍历 ProgramNode 中的所有语句并执行它们 case ClassTypeDefinitionNode classTypeDefinitionNode: // 定义类型 @@ -463,16 +481,18 @@ namespace Serein.Script throw new SereinSciptException(objectInstantiationNode, $"使用了未定义的类型\"{objectInstantiationNode.TypeName}\""); } - case FunctionCallNode callNode: + case FunctionCallNode callNode: // 调用方法 return await InterpretFunctionCallAsync(context, callNode); // 调用方法返回函数的返回值 - case MemberFunctionCallNode memberFunctionCallNode: + case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用 return await CallMemberFunction(context, memberFunctionCallNode); - case MemberAccessNode memberAccessNode: + case MemberAccessNode memberAccessNode: // 对象成员访问 return await GetValue(context, memberAccessNode); - case ReturnNode returnNode: // + case CollectionIndexNode collectionIndexNode: + return await GetCollectionValue(context, collectionIndexNode); + case ReturnNode returnNode: // 返回内容 return await EvaluateAsync(context, returnNode.Value); // 直接返回响应的内容 default: - throw new SereinSciptException(node, "解释器 EvaluateAsync() 未实现节点行为"); + throw new SereinSciptException(node, $"解释器 EvaluateAsync() 未实现{node}节点行为"); } } @@ -593,6 +613,74 @@ namespace Serein.Script return lastProperty.GetValue(target); } } + + /// + /// 获取集合中的成员 + /// + /// + /// + /// + public async Task 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 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}节点时,左值并非有效集合。"); + + } /// /// 缓存method委托 diff --git a/Serein.Script/SereinScriptParser.cs b/Serein.Script/SereinScriptParser.cs index 07b631c..63505ee 100644 --- a/Serein.Script/SereinScriptParser.cs +++ b/Serein.Script/SereinScriptParser.cs @@ -127,6 +127,11 @@ namespace Serein.Script // 对象成员的获取 return ParseMemberAccessOrAssignment(); } + else if (_tempToken.Type == TokenType.SquareBracketsLeft) + { + // 数组 index; 字典 key obj.Member[xxx]; + return ParseCollectionIndex(); + } else { // 不是函数调用,是变量赋值或其他 @@ -292,10 +297,13 @@ namespace Serein.Script public ASTNode ParseCollectionIndex() { - string functionName = _currentToken.Value.ToString(); - _currentToken = _lexer.NextToken(); // consume identifier + var identifierNode = new IdentifierNode(_currentToken.Value.ToString()).SetTokenInfo(_currentToken); - if (_currentToken.Type != TokenType.ParenthesisLeft) + string collectionName = _currentToken.Value.ToString(); + //_lexer.NextToken(); // consume "[" + _currentToken = _lexer.NextToken(); // consume identifier + // ParenthesisLeft + if (_currentToken.Type != TokenType.SquareBracketsLeft) throw new Exception("Expected '[' after function name"); _currentToken = _lexer.NextToken(); // consume "[" @@ -303,7 +311,7 @@ namespace Serein.Script ASTNode indexValue = Expression(); // get index value _currentToken = _lexer.NextToken(); // consume "]" - return new CollectionIndexNode(indexValue).SetTokenInfo(_currentToken); + return new CollectionIndexNode(identifierNode,indexValue).SetTokenInfo(_currentToken); } /// @@ -631,6 +639,14 @@ namespace Serein.Script { return ParseMemberAccessOrAssignment(); } + + + // 数组 index; 字典 key obj.Member[xxx]; + if (_identifierPeekToken.Type == TokenType.SquareBracketsLeft) + { + return ParseCollectionIndex(); + } + _currentToken = _lexer.NextToken(); // 消耗标识符 return new IdentifierNode(identifier.ToString()).SetTokenInfo(_currentToken); } diff --git a/Workbench/Themes/MethodDetailsControl.xaml b/Workbench/Themes/MethodDetailsControl.xaml index d83ca71..ce11b2a 100644 --- a/Workbench/Themes/MethodDetailsControl.xaml +++ b/Workbench/Themes/MethodDetailsControl.xaml @@ -60,7 +60,7 @@ - +