diff --git a/Library/FlowNode/FlowContext.cs b/Library/FlowNode/FlowContext.cs index e11ebc4..9e48a7e 100644 --- a/Library/FlowNode/FlowContext.cs +++ b/Library/FlowNode/FlowContext.cs @@ -27,13 +27,15 @@ namespace Serein.Library RunState = RunState.Running; } - private string _guid = global::System.Guid.NewGuid().ToString(); - /// /// 是否记录流程调用信息 /// public bool IsRecordInvokeInfo { get; set; } = true; - string IFlowContext.Guid => _guid; + + /// + /// 标识流程的Guid + /// + public string Guid { get; private set; } = global::System.Guid.NewGuid().ToString(); /// /// 运行环境 @@ -97,7 +99,7 @@ namespace Serein.Library FlowInvokeInfo flowInvokeInfo = new FlowInvokeInfo { - ContextGuid = this._guid, + ContextGuid = this.Guid, Id = id, PreviousNodeGuid = previousNode?.Guid, Method = theNode.MethodDetails?.MethodName, @@ -258,7 +260,7 @@ namespace Serein.Library NextOrientation = ConnectionInvokeType.None; RunState = RunState.Running; flowInvokeInfos.Clear(); - _guid = global::System.Guid.NewGuid().ToString(); + Guid = global::System.Guid.NewGuid().ToString(); } /// diff --git a/NodeFlow/Model/Nodes/SingleExpOpNode.cs b/NodeFlow/Model/Nodes/SingleExpOpNode.cs index de1cd92..2e7397c 100644 --- a/NodeFlow/Model/Nodes/SingleExpOpNode.cs +++ b/NodeFlow/Model/Nodes/SingleExpOpNode.cs @@ -69,6 +69,7 @@ namespace Serein.NodeFlow.Model.Nodes }; this.MethodDetails.ParameterDetailss = [.. pd]; + this.MethodDetails.ReturnType = typeof(object); } /// @@ -103,14 +104,12 @@ namespace Serein.NodeFlow.Model.Nodes { if(token.IsCancellationRequested) return FlowResult.Fail(this.Guid, context, "流程已通过token取消"); - object? parameter = null;// context.TransmissionData(this); // 表达式节点使用上一节点数据 + object? parameter = null;// 表达式节点使用上一节点数据 var pd = MethodDetails.ParameterDetailss[0]; var hasNode = context.Env.TryGetNodeModel(pd.ArgDataSourceNodeGuid, out var argSourceNode); if (!hasNode) { - /*context.NextOrientation = ConnectionInvokeType.IsError; - return new FlowResult(this.Guid, context);*/ parameter = null; } else @@ -130,14 +129,6 @@ namespace Serein.NodeFlow.Model.Nodes parameter = result.Value; } } - - /* - else - { - // 条件节点透传上一节点的数据 - parameter = context.TransmissionData(this.Guid); - } -*/ try { var result = await GetValueExpressionAsync(context, parameter, Expression); @@ -179,17 +170,18 @@ namespace Serein.NodeFlow.Model.Nodes // 表达式默认包含 “.” expression = $"return {expression};"; } - var resultType = getValueScript .ParserScript(expression, new Dictionary + var resultType = getValueScript.ParserScript(expression, new Dictionary { { dataName, dataType}, }); + } IScriptInvokeContext scriptContext = new ScriptInvokeContext(flowContext); scriptContext.SetVarValue(dataName, data); - var result = await getValueScript .InterpreterAsync(scriptContext); + var result = await getValueScript.InterpreterAsync(scriptContext); return result; } diff --git a/NodeFlow/Model/Nodes/SingleScriptNode.cs b/NodeFlow/Model/Nodes/SingleScriptNode.cs index e7700ca..e4f4227 100644 --- a/NodeFlow/Model/Nodes/SingleScriptNode.cs +++ b/NodeFlow/Model/Nodes/SingleScriptNode.cs @@ -49,6 +49,7 @@ namespace Serein.NodeFlow.Model.Nodes public SingleScriptNode(IFlowEnvironment environment) : base(environment) { sereinScript = new SereinScript(); + } static SingleScriptNode() @@ -78,9 +79,9 @@ namespace Serein.NodeFlow.Model.Nodes IsScriptChanged = true; } - /// - /// 节点创建时 - /// + /// + /// 节点创建时 + /// public override void OnCreating() { var md = MethodDetails; @@ -106,6 +107,38 @@ namespace Serein.NodeFlow.Model.Nodes } + /// + /// 更新节点返回类型 + /// + /// + private void UploadNodeReturnType(Type newType) + { + MethodDetails.ReturnType = newType; + + + foreach (var ct in NodeStaticConfig.ConnectionArgSourceTypes) + { + var newResultNodes = NeedResultNodes[ct].ToArray(); + foreach (var node in newResultNodes) + { + if(node is SingleScriptNode scriptNode) + { + var pds = scriptNode.MethodDetails.ParameterDetailss; + foreach (var pd in pds) + { + if (pd.ArgDataSourceType == ct && + pd.ArgDataSourceNodeGuid == this.Guid) + { + pd.DataType = newType; // 更新参数类型 + } + } + //scriptNode.ReloadScript(); // 重新加载目标脚本节点 + } + + } + } + } + /// /// 保存项目时保存脚本代码、方法入参类型、返回值类型 /// @@ -181,58 +214,77 @@ namespace Serein.NodeFlow.Model.Nodes } - - - + private object reloadLockObj = new object(); /// /// 重新加载脚本代码 /// public bool ReloadScript() { - try + lock (reloadLockObj) { - HashSet varNames = new HashSet(); - foreach (var pd in MethodDetails.ParameterDetailss) + if (!CheckRepeatParamter()) + return false; + var argTypes = GetParamterTypeInfo(); + try { - if (varNames.Contains(pd.Name)) - { - throw new Exception($"脚本节点重复的变量名称:{pd.Name} - {Guid}"); - } - varNames.Add(pd.Name); + var returnType = sereinScript.ParserScript(Script, argTypes); // 开始解析获取程序主节点 + UploadNodeReturnType(returnType); + } + catch (Exception ex) + { + SereinEnv.WriteLine(InfoType.WARN, ex.Message); + return false; // 解析失败 } - - var argTypes = MethodDetails.ParameterDetailss - .Select(pd => - { - if (pd.ArgDataSourceType == ConnectionArgSourceType.GetPreviousNodeData) - { - var Type = pd.DataType; - return (pd.Name, Type); - } - if (Env.TryGetNodeModel(pd.ArgDataSourceNodeGuid, out var node) && - node.MethodDetails?.ReturnType is not null) - { - pd.DataType = node.MethodDetails.ReturnType; - var Type = node.MethodDetails.ReturnType; - return (pd.Name, Type); - } - return default; - }) - .Where(x => x != default) - .ToDictionary(x => x.Name, x => x.Type); // 准备预定义类型 - - - var returnType = sereinScript.ParserScript(Script, argTypes); // 开始解析获取程序主节点 - MethodDetails.ReturnType = returnType; return true; } - catch (Exception ex) - { - SereinEnv.WriteLine(InfoType.WARN, ex.Message); - return false; // 解析失败 - } } - + + /// + /// 检查脚本参数是否有重复的名称 + /// + /// + private bool CheckRepeatParamter() + { + bool isSueccess = true; + HashSet varNames = new HashSet(); + foreach (var pd in MethodDetails.ParameterDetailss) + { + if (varNames.Contains(pd.Name)) + { + SereinEnv.WriteLine(InfoType.ERROR, $"脚本节点重复的变量名称:{pd.Name} - {Guid}"); + + isSueccess = false; + } + varNames.Add(pd.Name); + } + return isSueccess; + } + + /// + /// 获取参数类型信息 + /// + /// + private Dictionary GetParamterTypeInfo() + { + Dictionary argTypes = []; + var pds = MethodDetails.ParameterDetailss.ToArray(); + foreach (var pd in pds) + { + if (pd.ArgDataSourceType == ConnectionArgSourceType.GetPreviousNodeData) + { + argTypes[pd.Name] = pd.DataType; + } + if (Env.TryGetNodeModel(pd.ArgDataSourceNodeGuid, out var node) && + node.MethodDetails?.ReturnType is not null) + { + pd.DataType = node.MethodDetails.ReturnType; + var Type = node.MethodDetails.ReturnType; + argTypes[pd.Name] = Type; + } + } + return argTypes; + } + /// /// 转换为 C# 代码,并且附带方法信息 /// @@ -246,39 +298,11 @@ namespace Serein.NodeFlow.Model.Nodes methodName = $"FlowMethod_{tmp}"; } - HashSet varNames = new HashSet(); - foreach (var pd in MethodDetails.ParameterDetailss) - { - if (varNames.Contains(pd.Name)) - { - throw new Exception($"脚本节点重复的变量名称:{pd.Name} - {Guid}"); - } - varNames.Add(pd.Name); - } - - var argTypes = MethodDetails.ParameterDetailss - .Select(pd => - { - if(pd.ArgDataSourceType == ConnectionArgSourceType.GetPreviousNodeData) - { - var Type = pd.DataType; - return (pd.Name, Type); - } - if (Env.TryGetNodeModel(pd.ArgDataSourceNodeGuid, out var node) && - node.MethodDetails?.ReturnType is not null) - { - pd.DataType = node.MethodDetails.ReturnType; - var Type = node.MethodDetails.ReturnType; - return (pd.Name, Type); - } - return default; - }) - .Where(x => x != default) - .ToDictionary(x => x.Name, x => x.Type); // 准备预定义类型 - - + if (!CheckRepeatParamter()) + throw new Exception($"脚本节点入参重复"); + var argTypes = GetParamterTypeInfo(); var returnType = sereinScript.ParserScript(Script, argTypes); // 开始解析获取程序主节点 - MethodDetails.ReturnType = returnType; + UploadNodeReturnType(returnType); var scriptMethodInfo = sereinScript.ConvertCSharpCode(methodName, argTypes); return scriptMethodInfo; } @@ -297,6 +321,13 @@ namespace Serein.NodeFlow.Model.Nodes /// public override async Task ExecutingAsync(IFlowContext context, CancellationToken token) { + if (IsScriptChanged) + { + if (!ReloadScript()) + { + return FlowResult.Fail(this.Guid, context, "脚本解析失败,请检查脚本代码"); + } + } var result = await ExecutingAsync(this, context, token); return result; } @@ -311,6 +342,14 @@ namespace Serein.NodeFlow.Model.Nodes public async Task ExecutingAsync(NodeModelBase flowCallNode, IFlowContext context, CancellationToken token) { if (token.IsCancellationRequested) return FlowResult.Fail(this.Guid, context, "流程已通过token取消"); + if (IsScriptChanged) + { + if (!ReloadScript()) + { + return FlowResult.Fail(this.Guid, context, "脚本解析失败,请检查脚本代码"); + } + } + var @params = await flowCallNode.GetParametersAsync(context, token); IScriptInvokeContext scriptContext = new ScriptInvokeContext(context); diff --git a/NodeFlow/Model/Operations/ChangeNodeConnectionOperation.cs b/NodeFlow/Model/Operations/ChangeNodeConnectionOperation.cs index 31e4f55..4f3e63b 100644 --- a/NodeFlow/Model/Operations/ChangeNodeConnectionOperation.cs +++ b/NodeFlow/Model/Operations/ChangeNodeConnectionOperation.cs @@ -189,6 +189,7 @@ namespace Serein.NodeFlow.Model.Operations return false; } + if (ToNode.ControlType is not (NodeControlType.GlobalData or NodeControlType.ExpCondition or NodeControlType.ExpOp)) { @@ -199,6 +200,7 @@ namespace Serein.NodeFlow.Model.Operations } if (ToNode.MethodDetails.ParameterDetailss.Length > 0) { + var fromNoeReturnType = fromNode.MethodDetails.ReturnType; if (fromNoeReturnType != null && fromNoeReturnType != typeof(object) @@ -206,24 +208,33 @@ namespace Serein.NodeFlow.Model.Operations && fromNoeReturnType != typeof(Unit)) { var toNodePds = toNode.MethodDetails.ParameterDetailss; - foreach (ParameterDetails toNodePd in toNodePds) + if (toNodePds.Any(pd=>pd.IsExplicitData)) { - if (string.IsNullOrWhiteSpace(toNodePd.ArgDataSourceNodeGuid) // 入参没有设置数据来源节点 - && toNodePd.DataType.IsAssignableFrom(fromNoeReturnType)) // 返回值与目标入参相同(或可转换为目标入参) - { - - toPds.Add(toNodePd); - } - } - if (toPds.Count == 0) - { - var any = toNodePds.Any(pd => pd.ArgDataSourceNodeGuid == fromNode.Guid); // 判断目标节点是否已有该节点的连接 - checkTypeState = any; + checkTypeState = true; // 目标节点使用了显式的入参,无需关心参数是否匹配 } else { - checkTypeState = true; // 类型检查初步通过 + foreach (ParameterDetails toNodePd in toNodePds) + { + if (string.IsNullOrWhiteSpace(toNodePd.ArgDataSourceNodeGuid) // 入参没有设置数据来源节点 + && toNodePd.DataType.IsAssignableFrom(fromNoeReturnType)) // 返回值与目标入参相同(或可转换为目标入参) + { + + toPds.Add(toNodePd); + } + } + if (toPds.Count == 0) + { + + var any = toNodePds.Any(pd => pd.ArgDataSourceNodeGuid == fromNode.Guid); // 判断目标节点是否已有该节点的连接 + checkTypeState = any; + } + else + { + checkTypeState = true; // 类型检查初步通过 + } } + } } } diff --git a/Serein.Script/Node/ValueNode/NumberNode.cs b/Serein.Script/Node/ValueNode/NumberNode.cs index 7ad7162..13fc133 100644 --- a/Serein.Script/Node/ValueNode/NumberNode.cs +++ b/Serein.Script/Node/ValueNode/NumberNode.cs @@ -27,23 +27,23 @@ namespace Serein.Script.Node public class NumberIntNode(int vlaue) : NumberNode(vlaue) { } - + /// - /// int 整数型字面量 + /// long 整数型字面量 /// public class NumberLongNode(long vlaue) : NumberNode(vlaue) { } - + /// - /// int 整数型字面量 + /// float 字面量 /// public class NumberFloatNode(float vlaue) : NumberNode(vlaue) { } - + /// - /// int 整数型字面量 + /// double 字面量 /// public class NumberDoubleNode(double vlaue) : NumberNode(vlaue) { diff --git a/Serein.Script/SereinScriptInterpreter.cs b/Serein.Script/SereinScriptInterpreter.cs index dabdccf..171aba2 100644 --- a/Serein.Script/SereinScriptInterpreter.cs +++ b/Serein.Script/SereinScriptInterpreter.cs @@ -321,11 +321,11 @@ namespace Serein.Script async Task InterpreterFunctionCallNodeAsync(IScriptInvokeContext context, FunctionCallNode functionCallNode) { // 获取流程上下文 - if (context.FlowContext != null && functionCallNode.FunctionName.Equals("getFlowApi", StringComparison.OrdinalIgnoreCase)) + if (context.FlowContext != null && functionCallNode.FunctionName.Equals("getFlowContext", StringComparison.OrdinalIgnoreCase)) { return context.FlowContext; } - else if (functionCallNode.FunctionName.Equals("getScriptApi", StringComparison.OrdinalIgnoreCase)) + else if (functionCallNode.FunctionName.Equals("getScriptContext", StringComparison.OrdinalIgnoreCase)) { return context; } diff --git a/Serein.Script/SereinScriptParser.cs b/Serein.Script/SereinScriptParser.cs index 7d49aec..3439149 100644 --- a/Serein.Script/SereinScriptParser.cs +++ b/Serein.Script/SereinScriptParser.cs @@ -1087,7 +1087,7 @@ namespace Serein.Script } else if (_currentToken.Type == TokenType.NumberDouble) { - var value = float.Parse(_currentToken.Value); + var value = double.Parse(_currentToken.Value); NextToken(); // 消耗 double 浮点数 return new NumberDoubleNode(value).SetTokenInfo(factorToken); } diff --git a/Serein.Script/SereinScriptToCsharpScript.cs b/Serein.Script/SereinScriptToCsharpScript.cs index 9bccff8..5673bcb 100644 --- a/Serein.Script/SereinScriptToCsharpScript.cs +++ b/Serein.Script/SereinScriptToCsharpScript.cs @@ -12,7 +12,7 @@ namespace Serein.Script { public const string ClassName = nameof(SereinScriptToCsharpScript); - public SereinScriptMethodInfo sereinScriptMethodInfo ; + public SereinScriptMethodInfo sereinScriptMethodInfo; /// /// 符号表 @@ -51,6 +51,13 @@ namespace Serein.Script _codeBuilder.Append(code); } + private void CompleteCurrentStatement() + { + _codeBuilder.Append($";{Environment.NewLine}"); + + } + private string Tab => new string (' ', _indentLevel* 4); + private void Indent() => _indentLevel++; private void Unindent() => _indentLevel--; @@ -67,7 +74,7 @@ namespace Serein.Script }; var sb = _codeBuilder; var methodResultType = _symbolInfos[programNode]; - if(methodResultType == typeof(void)) + if (methodResultType == typeof(void)) { methodResultType = typeof(object); } @@ -85,9 +92,9 @@ namespace Serein.Script } AppendLine($"public partial class {ClassName}"); - AppendLine( "{"); + AppendLine("{"); Indent(); - if(param is null || param.Count == 0) + if (param is null || param.Count == 0) { // 生成方法签名 AppendLine($"public static {returnContent} {mehtodName}()"); @@ -97,15 +104,15 @@ namespace Serein.Script // 生成方法签名 AppendLine($"public static {returnContent} {mehtodName}({GetMethodParamster(param)})"); } - AppendLine( "{"); + AppendLine("{"); Indent(); // 生成变量节点 var idfNodesTemp = _symbolInfos.Keys.Where(key => key is IdentifierNode) - .OfType().ToList() ; + .OfType().ToList(); var idfNodes = (param is null) switch { true => idfNodesTemp.DistinctBy(n => n.Name).ToList(), - false => idfNodesTemp.DistinctBy(n => n.Name).DistinctByCondition(n => !param.ContainsKey(n.Name) ).ToList(), + false => idfNodesTemp.DistinctBy(n => n.Name).DistinctByCondition(n => !param.ContainsKey(n.Name)).ToList(), }; foreach (var idf in idfNodes) { @@ -116,10 +123,13 @@ namespace Serein.Script AppendLine(""); // 递归遍历节点生成代码 - foreach (var stmt in programNode.Statements) + foreach (var stmt in programNode.Statements) { ConvertCode(stmt); - Append(";"); + if (stmt is not (IfNode or WhileNode)) + { + CompleteCurrentStatement(); + } } if (_symbolInfos[programNode] == typeof(void)) { @@ -158,7 +168,7 @@ namespace Serein.Script return string.Join(',', values); } - private void ConvertCode( ASTNode node) + private void ConvertCode(ASTNode node) { switch (node) { @@ -167,16 +177,16 @@ namespace Serein.Script case ReturnNode returnNode: // 程序退出节点 void ConvertCodeOfReturnNode(ReturnNode returnNode) { + + Append(Tab); if (returnNode.Value is not null) { Append($"return "); ConvertCode(returnNode.Value); - Append(";"); - AppendLine(string.Empty); } else { - AppendLine("return defult;"); + AppendLine("return defult"); } } ConvertCodeOfReturnNode(returnNode); @@ -205,49 +215,30 @@ namespace Serein.Script break; case NumberDoubleNode numberDoubleNode: // double浮点数值字面量 Append($"{numberDoubleNode.Value}d"); - break; + break; #endregion case IdentifierNode identifierNode: // 变量定义 void ConvertCodeOfIdentifierNode(IdentifierNode identifierNode) { var varName = identifierNode.Name; Append(varName); - /*if (_local.TryGetValue(varName, out var type)) - { - // 定义过,需要使用变量 - Append(varName); - } - else - { - if (_symbolInfos.TryGetValue(identifierNode, out type)) - { - // 不存在,定义变量 - Append($"global::{type.FullName} {varName}"); - _local[varName] = type; - //Append(varName); - } - else - { - throw new Exception($"加载符号表时,无法匹配 IdentifierNode 节点的类型。 name : {varName}"); - } - }*/ } ConvertCodeOfIdentifierNode(identifierNode); break; case IfNode ifNode: // if语句结构 void ConvertCodeOfIfNode(IfNode ifNOde) { - AppendLine(""); - Append($"if("); + + Append($"{Tab}if("); ConvertCode(ifNOde.Condition); // 解析条件 - Append($" == true)"); + Append($" == true){Environment.NewLine}"); AppendLine("{"); Indent(); - foreach(var item in ifNOde.TrueBranch) + foreach (var item in ifNOde.TrueBranch) { ConvertCode(item); - AppendLine(string.Empty); - } + CompleteCurrentStatement(); + } Unindent(); AppendLine("}"); AppendLine("else"); @@ -256,7 +247,7 @@ namespace Serein.Script foreach (var item in ifNOde.FalseBranch) { ConvertCode(item); - AppendLine(string.Empty); + CompleteCurrentStatement(); } Unindent(); AppendLine("}"); @@ -275,8 +266,7 @@ namespace Serein.Script foreach (var item in whileNode.Body) { ConvertCode(item); - Append(";"); - AppendLine(string.Empty); + CompleteCurrentStatement(); } Unindent(); AppendLine("}"); @@ -286,6 +276,8 @@ namespace Serein.Script case AssignmentNode assignmentNode: // 变量赋值语句 void ConvertCodeOfAssignmentNode(AssignmentNode assignmentNode) { + + Append(Tab); ConvertCode(assignmentNode.Target); Append(" = "); if (assignmentNode.Value is null) @@ -296,19 +288,17 @@ namespace Serein.Script { ConvertCode(assignmentNode.Value); } - Append(";"); - AppendLine(string.Empty); } ConvertCodeOfAssignmentNode(assignmentNode); break; case BinaryOperationNode binaryOperationNode: // 二元运算操作 void ConvertCodeOfBinaryOperationNode(BinaryOperationNode binaryOperationNode) { - Append("("); + Append("("); ConvertCode(binaryOperationNode.Left); // 左操作数 Append(binaryOperationNode.Operator); // 操作符 ConvertCode(binaryOperationNode.Right); // 左操作数 - Append(")"); + Append(")"); } ConvertCodeOfBinaryOperationNode(binaryOperationNode); break; @@ -318,7 +308,6 @@ namespace Serein.Script ConvertCode(collectionAssignmentNode.Collection); Append(" = "); ConvertCode(collectionAssignmentNode.Value); - Append(";"); AppendLine(string.Empty); } ConvertCodeOfCollectionAssignmentNode(collectionAssignmentNode); @@ -333,6 +322,25 @@ namespace Serein.Script } ConvertCodeOfCollectionIndexNode(collectionIndexNode); break; + case ArrayDefintionNode arrayDefintionNode: + void ConvertCodeOfArrayDefintionNode(ArrayDefintionNode arrayDefintionNode) + { + var arrType = this._symbolInfos[arrayDefintionNode]; + var tab = new string(' ', (_indentLevel + 1) * 4); + Append($"new global::{arrType.FullName}{{{Environment.NewLine}"); + for (int index = 0; index < arrayDefintionNode.Elements.Count; index++) + { + ASTNode? e = arrayDefintionNode.Elements[index]; + Append(tab + " "); + ConvertCode(e); + if (index < arrayDefintionNode.Elements.Count - 1) + Append($", {Environment.NewLine}"); + + } + Append($"{Environment.NewLine}{tab}}}"); + } + ConvertCodeOfArrayDefintionNode(arrayDefintionNode); + break; case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义 void ConvertCodeOfClassTypeDefinitionNode(ClassTypeDefinitionNode classTypeDefinitionNode) { @@ -409,7 +417,7 @@ namespace Serein.Script ConvertCode(memberAccessNode.Object); Append($".{memberAccessNode.MemberName}"); } - ConvertCodeOfMemberAccessNode(memberAccessNode); + ConvertCodeOfMemberAccessNode(memberAccessNode); break; case MemberAssignmentNode memberAssignmentNode: // 对象成员赋值 void ConvertCodeOfMemberAssignmentNode(MemberAssignmentNode memberAssignmentNode) @@ -417,10 +425,8 @@ namespace Serein.Script ConvertCode(memberAssignmentNode.Object); Append($".{memberAssignmentNode.MemberName} = "); ConvertCode(memberAssignmentNode.Value); - Append($";"); - AppendLine(string.Empty); } - ConvertCodeOfMemberAssignmentNode(memberAssignmentNode); + ConvertCodeOfMemberAssignmentNode(memberAssignmentNode); break; case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用 void ConvertCodeOfMemberFunctionCallNode(MemberFunctionCallNode memberFunctionCallNode) @@ -450,7 +456,7 @@ namespace Serein.Script } - ConvertCodeOfMemberFunctionCallNode(memberFunctionCallNode); + ConvertCodeOfMemberFunctionCallNode(memberFunctionCallNode); break; case FunctionCallNode functionCallNode: // 外部挂载的函数调用 void ConvertCodeOfFunctionCallNode(FunctionCallNode functionCallNode) @@ -462,13 +468,13 @@ namespace Serein.Script } var funcName = functionCallNode.FunctionName switch { - "int" => "@int" , - "bool" => "@bool" , - "double" => "@double" , - "long" => "@long" , - "decimal" => "@decimal" , - "float" => "@float" , - "byte" => "@byte" , + "int" => "@int", + "bool" => "@bool", + "double" => "@double", + "long" => "@long", + "decimal" => "@decimal", + "float" => "@float", + "byte" => "@byte", _ => functionCallNode.FunctionName, }; @@ -495,6 +501,9 @@ namespace Serein.Script } } + + + } diff --git a/Serein.Script/SereinScriptTypeAnalysis.cs b/Serein.Script/SereinScriptTypeAnalysis.cs index d07e4f3..f6d0f5d 100644 --- a/Serein.Script/SereinScriptTypeAnalysis.cs +++ b/Serein.Script/SereinScriptTypeAnalysis.cs @@ -1,4 +1,5 @@ using Serein.Library; +using Serein.Library.Api; using Serein.Library.Utils; using Serein.Script.Node; using Serein.Script.Node.FlowControl; @@ -105,10 +106,20 @@ namespace Serein.Script case ReturnNode returnNode: // 程序退出节点 Type AnalysisReturnNode(ReturnNode returnNode) { - var resultType = Analysis(returnNode.Value); - NodeSymbolInfos[returnNode.Value] = resultType; - NodeSymbolInfos[returnNode] = resultType; - return resultType; + if(returnNode.Value is null) + { + var resultType = typeof(void); + NodeSymbolInfos[returnNode] = resultType; + return resultType; + } + else + { + var resultType = Analysis(returnNode.Value); + NodeSymbolInfos[returnNode.Value] = resultType; + NodeSymbolInfos[returnNode] = resultType; + return resultType; + } + } return AnalysisReturnNode(returnNode); case NullNode nullNode: // null @@ -406,9 +417,25 @@ namespace Serein.Script { var objectType = Analysis(memberFunctionCallNode.Object); var types = memberFunctionCallNode.Arguments.Select(arg => Analysis(arg)).ToArray(); + + var methodInfo = objectType.GetMethod(memberFunctionCallNode.FunctionName, types); if (methodInfo is null) - throw new Exception($"类型 {objectType} 没有方法 {memberFunctionCallNode.FunctionName}"); + { + var t = objectType.GetMethods().Where(m => m.Name.Equals(memberFunctionCallNode.FunctionName)).ToArray(); + if(t.Length > 0) + { + var content = string.Join($";{Environment.NewLine}", t.Select(m => m.ToString())); + throw new Exception($"类型 {objectType} 没有指定的重载方法 " + + $"{memberFunctionCallNode.FunctionName}({string.Join(",", types.Select(t => t.Name))})," + + $"但存在其它重载方法:{content}"); + } + else + { + throw new Exception($"类型 {objectType} 没有方法 {memberFunctionCallNode.FunctionName}"); + } + } + for (int index = 0; index < memberFunctionCallNode.Arguments.Count; index++) { ASTNode argNode = memberFunctionCallNode.Arguments[index]; @@ -428,7 +455,17 @@ namespace Serein.Script case FunctionCallNode functionCallNode: // 外部挂载的函数调用 Type AnalysisFunctionCallNode(FunctionCallNode functionCallNode) { - if(!SereinScript.FunctionInfos.TryGetValue(functionCallNode.FunctionName, out var methodInfo)) + // 获取流程上下文 + if (functionCallNode.FunctionName.Equals("getFlowContext", StringComparison.OrdinalIgnoreCase)) + { + return typeof(IFlowContext); + } + else if (functionCallNode.FunctionName.Equals("getScriptContext", StringComparison.OrdinalIgnoreCase)) + { + return typeof(IScriptInvokeContext); + } + + if (!SereinScript.FunctionInfos.TryGetValue(functionCallNode.FunctionName, out var methodInfo)) { throw new Exception($"脚本没有挂载方法 {functionCallNode.FunctionName}"); } diff --git a/Workbench/Views/FlowCanvasView.xaml.cs b/Workbench/Views/FlowCanvasView.xaml.cs index 224800a..024a2fc 100644 --- a/Workbench/Views/FlowCanvasView.xaml.cs +++ b/Workbench/Views/FlowCanvasView.xaml.cs @@ -1281,7 +1281,7 @@ namespace Serein.Workbench.Views private ContextMenu ConfiguerSelectionRectangle() { var contextMenu = new ContextMenu(); - contextMenu.Items.Add(WpfFuncTool.CreateMenuItem("删除", (s, e) => + /*contextMenu.Items.Add(WpfFuncTool.CreateMenuItem("删除", (s, e) => { if (selectNodeControls.Count > 0) { @@ -1296,7 +1296,7 @@ namespace Serein.Workbench.Views } } SelectionRectangle.Visibility = Visibility.Collapsed; - })); + }));*/ return contextMenu; // nodeControl.ContextMenu = contextMenu; }