1. 新增了脚本节点之间连接时,入参类型伴随来源节点的返回类型改变而改变。

2. 重新优化了Script项目脚本生成代码的缩进排版
3. 修复了Script中对于Double字面量错误的使用了Float解析的bug
This commit is contained in:
fengjiayi
2025-07-31 15:45:02 +08:00
parent 827a9242ae
commit 5f6a58168a
10 changed files with 273 additions and 183 deletions

View File

@@ -27,13 +27,15 @@ namespace Serein.Library
RunState = RunState.Running; RunState = RunState.Running;
} }
private string _guid = global::System.Guid.NewGuid().ToString();
/// <summary> /// <summary>
/// 是否记录流程调用信息 /// 是否记录流程调用信息
/// </summary> /// </summary>
public bool IsRecordInvokeInfo { get; set; } = true; public bool IsRecordInvokeInfo { get; set; } = true;
string IFlowContext.Guid => _guid;
/// <summary>
/// 标识流程的Guid
/// </summary>
public string Guid { get; private set; } = global::System.Guid.NewGuid().ToString();
/// <summary> /// <summary>
/// 运行环境 /// 运行环境
@@ -97,7 +99,7 @@ namespace Serein.Library
FlowInvokeInfo flowInvokeInfo = new FlowInvokeInfo FlowInvokeInfo flowInvokeInfo = new FlowInvokeInfo
{ {
ContextGuid = this._guid, ContextGuid = this.Guid,
Id = id, Id = id,
PreviousNodeGuid = previousNode?.Guid, PreviousNodeGuid = previousNode?.Guid,
Method = theNode.MethodDetails?.MethodName, Method = theNode.MethodDetails?.MethodName,
@@ -258,7 +260,7 @@ namespace Serein.Library
NextOrientation = ConnectionInvokeType.None; NextOrientation = ConnectionInvokeType.None;
RunState = RunState.Running; RunState = RunState.Running;
flowInvokeInfos.Clear(); flowInvokeInfos.Clear();
_guid = global::System.Guid.NewGuid().ToString(); Guid = global::System.Guid.NewGuid().ToString();
} }
/// <summary> /// <summary>

View File

@@ -69,6 +69,7 @@ namespace Serein.NodeFlow.Model.Nodes
}; };
this.MethodDetails.ParameterDetailss = [.. pd]; this.MethodDetails.ParameterDetailss = [.. pd];
this.MethodDetails.ReturnType = typeof(object);
} }
/// <summary> /// <summary>
@@ -103,14 +104,12 @@ namespace Serein.NodeFlow.Model.Nodes
{ {
if(token.IsCancellationRequested) return FlowResult.Fail(this.Guid, context, "流程已通过token取消"); 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 pd = MethodDetails.ParameterDetailss[0];
var hasNode = context.Env.TryGetNodeModel(pd.ArgDataSourceNodeGuid, out var argSourceNode); var hasNode = context.Env.TryGetNodeModel(pd.ArgDataSourceNodeGuid, out var argSourceNode);
if (!hasNode) if (!hasNode)
{ {
/*context.NextOrientation = ConnectionInvokeType.IsError;
return new FlowResult(this.Guid, context);*/
parameter = null; parameter = null;
} }
else else
@@ -130,14 +129,6 @@ namespace Serein.NodeFlow.Model.Nodes
parameter = result.Value; parameter = result.Value;
} }
} }
/*
else
{
// 条件节点透传上一节点的数据
parameter = context.TransmissionData(this.Guid);
}
*/
try try
{ {
var result = await GetValueExpressionAsync(context, parameter, Expression); var result = await GetValueExpressionAsync(context, parameter, Expression);
@@ -179,17 +170,18 @@ namespace Serein.NodeFlow.Model.Nodes
// 表达式默认包含 “.” // 表达式默认包含 “.”
expression = $"return {expression};"; expression = $"return {expression};";
} }
var resultType = getValueScript .ParserScript(expression, new Dictionary<string, Type> var resultType = getValueScript.ParserScript(expression, new Dictionary<string, Type>
{ {
{ dataName, dataType}, { dataName, dataType},
}); });
} }
IScriptInvokeContext scriptContext = new ScriptInvokeContext(flowContext); IScriptInvokeContext scriptContext = new ScriptInvokeContext(flowContext);
scriptContext.SetVarValue(dataName, data); scriptContext.SetVarValue(dataName, data);
var result = await getValueScript .InterpreterAsync(scriptContext); var result = await getValueScript.InterpreterAsync(scriptContext);
return result; return result;
} }

View File

@@ -49,6 +49,7 @@ namespace Serein.NodeFlow.Model.Nodes
public SingleScriptNode(IFlowEnvironment environment) : base(environment) public SingleScriptNode(IFlowEnvironment environment) : base(environment)
{ {
sereinScript = new SereinScript(); sereinScript = new SereinScript();
} }
static SingleScriptNode() static SingleScriptNode()
@@ -78,9 +79,9 @@ namespace Serein.NodeFlow.Model.Nodes
IsScriptChanged = true; IsScriptChanged = true;
} }
/// <summary> /// <summary>
/// 节点创建时 /// 节点创建时
/// </summary> /// </summary>
public override void OnCreating() public override void OnCreating()
{ {
var md = MethodDetails; var md = MethodDetails;
@@ -106,6 +107,38 @@ namespace Serein.NodeFlow.Model.Nodes
} }
/// <summary>
/// 更新节点返回类型
/// </summary>
/// <param name="newType"></param>
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(); // 重新加载目标脚本节点
}
}
}
}
/// <summary> /// <summary>
/// 保存项目时保存脚本代码、方法入参类型、返回值类型 /// 保存项目时保存脚本代码、方法入参类型、返回值类型
/// </summary> /// </summary>
@@ -181,56 +214,75 @@ namespace Serein.NodeFlow.Model.Nodes
} }
private object reloadLockObj = new object();
/// <summary> /// <summary>
/// 重新加载脚本代码 /// 重新加载脚本代码
/// </summary> /// </summary>
public bool ReloadScript() public bool ReloadScript()
{ {
try lock (reloadLockObj)
{ {
HashSet<string> varNames = new HashSet<string>(); if (!CheckRepeatParamter())
foreach (var pd in MethodDetails.ParameterDetailss) return false;
var argTypes = GetParamterTypeInfo();
try
{ {
if (varNames.Contains(pd.Name)) var returnType = sereinScript.ParserScript(Script, argTypes); // 开始解析获取程序主节点
{ UploadNodeReturnType(returnType);
throw new Exception($"脚本节点重复的变量名称:{pd.Name} - {Guid}"); }
} catch (Exception ex)
varNames.Add(pd.Name); {
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; return true;
} }
catch (Exception ex) }
/// <summary>
/// 检查脚本参数是否有重复的名称
/// </summary>
/// <returns></returns>
private bool CheckRepeatParamter()
{
bool isSueccess = true;
HashSet<string> varNames = new HashSet<string>();
foreach (var pd in MethodDetails.ParameterDetailss)
{ {
SereinEnv.WriteLine(InfoType.WARN, ex.Message); if (varNames.Contains(pd.Name))
return false; // 解析失败 {
SereinEnv.WriteLine(InfoType.ERROR, $"脚本节点重复的变量名称:{pd.Name} - {Guid}");
isSueccess = false;
}
varNames.Add(pd.Name);
} }
return isSueccess;
}
/// <summary>
/// 获取参数类型信息
/// </summary>
/// <returns></returns>
private Dictionary<string, Type> GetParamterTypeInfo()
{
Dictionary<string, Type> 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;
} }
/// <summary> /// <summary>
@@ -246,39 +298,11 @@ namespace Serein.NodeFlow.Model.Nodes
methodName = $"FlowMethod_{tmp}"; methodName = $"FlowMethod_{tmp}";
} }
HashSet<string> varNames = new HashSet<string>(); if (!CheckRepeatParamter())
foreach (var pd in MethodDetails.ParameterDetailss) throw new Exception($"脚本节点入参重复");
{ var argTypes = GetParamterTypeInfo();
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); // 准备预定义类型
var returnType = sereinScript.ParserScript(Script, argTypes); // 开始解析获取程序主节点 var returnType = sereinScript.ParserScript(Script, argTypes); // 开始解析获取程序主节点
MethodDetails.ReturnType = returnType; UploadNodeReturnType(returnType);
var scriptMethodInfo = sereinScript.ConvertCSharpCode(methodName, argTypes); var scriptMethodInfo = sereinScript.ConvertCSharpCode(methodName, argTypes);
return scriptMethodInfo; return scriptMethodInfo;
} }
@@ -297,6 +321,13 @@ namespace Serein.NodeFlow.Model.Nodes
/// <returns></returns> /// <returns></returns>
public override async Task<FlowResult> ExecutingAsync(IFlowContext context, CancellationToken token) public override async Task<FlowResult> ExecutingAsync(IFlowContext context, CancellationToken token)
{ {
if (IsScriptChanged)
{
if (!ReloadScript())
{
return FlowResult.Fail(this.Guid, context, "脚本解析失败,请检查脚本代码");
}
}
var result = await ExecutingAsync(this, context, token); var result = await ExecutingAsync(this, context, token);
return result; return result;
} }
@@ -311,6 +342,14 @@ namespace Serein.NodeFlow.Model.Nodes
public async Task<FlowResult> ExecutingAsync(NodeModelBase flowCallNode, IFlowContext context, CancellationToken token) public async Task<FlowResult> ExecutingAsync(NodeModelBase flowCallNode, IFlowContext context, CancellationToken token)
{ {
if (token.IsCancellationRequested) return FlowResult.Fail(this.Guid, context, "流程已通过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); var @params = await flowCallNode.GetParametersAsync(context, token);
IScriptInvokeContext scriptContext = new ScriptInvokeContext(context); IScriptInvokeContext scriptContext = new ScriptInvokeContext(context);

View File

@@ -189,6 +189,7 @@ namespace Serein.NodeFlow.Model.Operations
return false; return false;
} }
if (ToNode.ControlType is not (NodeControlType.GlobalData or NodeControlType.ExpCondition or NodeControlType.ExpOp)) 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) if (ToNode.MethodDetails.ParameterDetailss.Length > 0)
{ {
var fromNoeReturnType = fromNode.MethodDetails.ReturnType; var fromNoeReturnType = fromNode.MethodDetails.ReturnType;
if (fromNoeReturnType != null if (fromNoeReturnType != null
&& fromNoeReturnType != typeof(object) && fromNoeReturnType != typeof(object)
@@ -206,24 +208,33 @@ namespace Serein.NodeFlow.Model.Operations
&& fromNoeReturnType != typeof(Unit)) && fromNoeReturnType != typeof(Unit))
{ {
var toNodePds = toNode.MethodDetails.ParameterDetailss; var toNodePds = toNode.MethodDetails.ParameterDetailss;
foreach (ParameterDetails toNodePd in toNodePds) if (toNodePds.Any(pd=>pd.IsExplicitData))
{ {
if (string.IsNullOrWhiteSpace(toNodePd.ArgDataSourceNodeGuid) // 入参没有设置数据来源节点 checkTypeState = true; // 目标节点使用了显式的入参,无需关心参数是否匹配
&& toNodePd.DataType.IsAssignableFrom(fromNoeReturnType)) // 返回值与目标入参相同(或可转换为目标入参)
{
toPds.Add(toNodePd);
}
}
if (toPds.Count == 0)
{
var any = toNodePds.Any(pd => pd.ArgDataSourceNodeGuid == fromNode.Guid); // 判断目标节点是否已有该节点的连接
checkTypeState = any;
} }
else 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; // 类型检查初步通过
}
} }
} }
} }
} }

View File

@@ -29,21 +29,21 @@ namespace Serein.Script.Node
} }
/// <summary> /// <summary>
/// int 整数型字面量 /// long 整数型字面量
/// </summary> /// </summary>
public class NumberLongNode(long vlaue) : NumberNode<long>(vlaue) public class NumberLongNode(long vlaue) : NumberNode<long>(vlaue)
{ {
} }
/// <summary> /// <summary>
/// int 整数型字面量 /// float 字面量
/// </summary> /// </summary>
public class NumberFloatNode(float vlaue) : NumberNode<float>(vlaue) public class NumberFloatNode(float vlaue) : NumberNode<float>(vlaue)
{ {
} }
/// <summary> /// <summary>
/// int 整数型字面量 /// double 字面量
/// </summary> /// </summary>
public class NumberDoubleNode(double vlaue) : NumberNode<double>(vlaue) public class NumberDoubleNode(double vlaue) : NumberNode<double>(vlaue)
{ {

View File

@@ -321,11 +321,11 @@ namespace Serein.Script
async Task<object?> InterpreterFunctionCallNodeAsync(IScriptInvokeContext context, FunctionCallNode functionCallNode) async Task<object?> 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; return context.FlowContext;
} }
else if (functionCallNode.FunctionName.Equals("getScriptApi", StringComparison.OrdinalIgnoreCase)) else if (functionCallNode.FunctionName.Equals("getScriptContext", StringComparison.OrdinalIgnoreCase))
{ {
return context; return context;
} }

View File

@@ -1087,7 +1087,7 @@ namespace Serein.Script
} }
else if (_currentToken.Type == TokenType.NumberDouble) else if (_currentToken.Type == TokenType.NumberDouble)
{ {
var value = float.Parse(_currentToken.Value); var value = double.Parse(_currentToken.Value);
NextToken(); // 消耗 double 浮点数 NextToken(); // 消耗 double 浮点数
return new NumberDoubleNode(value).SetTokenInfo(factorToken); return new NumberDoubleNode(value).SetTokenInfo(factorToken);
} }

View File

@@ -12,7 +12,7 @@ namespace Serein.Script
{ {
public const string ClassName = nameof(SereinScriptToCsharpScript); public const string ClassName = nameof(SereinScriptToCsharpScript);
public SereinScriptMethodInfo sereinScriptMethodInfo ; public SereinScriptMethodInfo sereinScriptMethodInfo;
/// <summary> /// <summary>
/// 符号表 /// 符号表
@@ -51,6 +51,13 @@ namespace Serein.Script
_codeBuilder.Append(code); _codeBuilder.Append(code);
} }
private void CompleteCurrentStatement()
{
_codeBuilder.Append($";{Environment.NewLine}");
}
private string Tab => new string (' ', _indentLevel* 4);
private void Indent() => _indentLevel++; private void Indent() => _indentLevel++;
private void Unindent() => _indentLevel--; private void Unindent() => _indentLevel--;
@@ -67,7 +74,7 @@ namespace Serein.Script
}; };
var sb = _codeBuilder; var sb = _codeBuilder;
var methodResultType = _symbolInfos[programNode]; var methodResultType = _symbolInfos[programNode];
if(methodResultType == typeof(void)) if (methodResultType == typeof(void))
{ {
methodResultType = typeof(object); methodResultType = typeof(object);
} }
@@ -85,9 +92,9 @@ namespace Serein.Script
} }
AppendLine($"public partial class {ClassName}"); AppendLine($"public partial class {ClassName}");
AppendLine( "{"); AppendLine("{");
Indent(); Indent();
if(param is null || param.Count == 0) if (param is null || param.Count == 0)
{ {
// 生成方法签名 // 生成方法签名
AppendLine($"public static {returnContent} {mehtodName}()"); AppendLine($"public static {returnContent} {mehtodName}()");
@@ -97,15 +104,15 @@ namespace Serein.Script
// 生成方法签名 // 生成方法签名
AppendLine($"public static {returnContent} {mehtodName}({GetMethodParamster(param)})"); AppendLine($"public static {returnContent} {mehtodName}({GetMethodParamster(param)})");
} }
AppendLine( "{"); AppendLine("{");
Indent(); Indent();
// 生成变量节点 // 生成变量节点
var idfNodesTemp = _symbolInfos.Keys.Where(key => key is IdentifierNode) var idfNodesTemp = _symbolInfos.Keys.Where(key => key is IdentifierNode)
.OfType<IdentifierNode>().ToList() ; .OfType<IdentifierNode>().ToList();
var idfNodes = (param is null) switch var idfNodes = (param is null) switch
{ {
true => idfNodesTemp.DistinctBy(n => n.Name).ToList(), 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) foreach (var idf in idfNodes)
{ {
@@ -119,7 +126,10 @@ namespace Serein.Script
foreach (var stmt in programNode.Statements) foreach (var stmt in programNode.Statements)
{ {
ConvertCode(stmt); ConvertCode(stmt);
Append(";"); if (stmt is not (IfNode or WhileNode))
{
CompleteCurrentStatement();
}
} }
if (_symbolInfos[programNode] == typeof(void)) if (_symbolInfos[programNode] == typeof(void))
{ {
@@ -158,7 +168,7 @@ namespace Serein.Script
return string.Join(',', values); return string.Join(',', values);
} }
private void ConvertCode( ASTNode node) private void ConvertCode(ASTNode node)
{ {
switch (node) switch (node)
{ {
@@ -167,16 +177,16 @@ namespace Serein.Script
case ReturnNode returnNode: // 程序退出节点 case ReturnNode returnNode: // 程序退出节点
void ConvertCodeOfReturnNode(ReturnNode returnNode) void ConvertCodeOfReturnNode(ReturnNode returnNode)
{ {
Append(Tab);
if (returnNode.Value is not null) if (returnNode.Value is not null)
{ {
Append($"return "); Append($"return ");
ConvertCode(returnNode.Value); ConvertCode(returnNode.Value);
Append(";");
AppendLine(string.Empty);
} }
else else
{ {
AppendLine("return defult;"); AppendLine("return defult");
} }
} }
ConvertCodeOfReturnNode(returnNode); ConvertCodeOfReturnNode(returnNode);
@@ -212,41 +222,22 @@ namespace Serein.Script
{ {
var varName = identifierNode.Name; var varName = identifierNode.Name;
Append(varName); 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); ConvertCodeOfIdentifierNode(identifierNode);
break; break;
case IfNode ifNode: // if语句结构 case IfNode ifNode: // if语句结构
void ConvertCodeOfIfNode(IfNode ifNOde) void ConvertCodeOfIfNode(IfNode ifNOde)
{ {
AppendLine("");
Append($"if("); Append($"{Tab}if(");
ConvertCode(ifNOde.Condition); // 解析条件 ConvertCode(ifNOde.Condition); // 解析条件
Append($" == true)"); Append($" == true){Environment.NewLine}");
AppendLine("{"); AppendLine("{");
Indent(); Indent();
foreach(var item in ifNOde.TrueBranch) foreach (var item in ifNOde.TrueBranch)
{ {
ConvertCode(item); ConvertCode(item);
AppendLine(string.Empty); CompleteCurrentStatement();
} }
Unindent(); Unindent();
AppendLine("}"); AppendLine("}");
@@ -256,7 +247,7 @@ namespace Serein.Script
foreach (var item in ifNOde.FalseBranch) foreach (var item in ifNOde.FalseBranch)
{ {
ConvertCode(item); ConvertCode(item);
AppendLine(string.Empty); CompleteCurrentStatement();
} }
Unindent(); Unindent();
AppendLine("}"); AppendLine("}");
@@ -275,8 +266,7 @@ namespace Serein.Script
foreach (var item in whileNode.Body) foreach (var item in whileNode.Body)
{ {
ConvertCode(item); ConvertCode(item);
Append(";"); CompleteCurrentStatement();
AppendLine(string.Empty);
} }
Unindent(); Unindent();
AppendLine("}"); AppendLine("}");
@@ -286,6 +276,8 @@ namespace Serein.Script
case AssignmentNode assignmentNode: // 变量赋值语句 case AssignmentNode assignmentNode: // 变量赋值语句
void ConvertCodeOfAssignmentNode(AssignmentNode assignmentNode) void ConvertCodeOfAssignmentNode(AssignmentNode assignmentNode)
{ {
Append(Tab);
ConvertCode(assignmentNode.Target); ConvertCode(assignmentNode.Target);
Append(" = "); Append(" = ");
if (assignmentNode.Value is null) if (assignmentNode.Value is null)
@@ -296,8 +288,6 @@ namespace Serein.Script
{ {
ConvertCode(assignmentNode.Value); ConvertCode(assignmentNode.Value);
} }
Append(";");
AppendLine(string.Empty);
} }
ConvertCodeOfAssignmentNode(assignmentNode); ConvertCodeOfAssignmentNode(assignmentNode);
break; break;
@@ -318,7 +308,6 @@ namespace Serein.Script
ConvertCode(collectionAssignmentNode.Collection); ConvertCode(collectionAssignmentNode.Collection);
Append(" = "); Append(" = ");
ConvertCode(collectionAssignmentNode.Value); ConvertCode(collectionAssignmentNode.Value);
Append(";");
AppendLine(string.Empty); AppendLine(string.Empty);
} }
ConvertCodeOfCollectionAssignmentNode(collectionAssignmentNode); ConvertCodeOfCollectionAssignmentNode(collectionAssignmentNode);
@@ -333,6 +322,25 @@ namespace Serein.Script
} }
ConvertCodeOfCollectionIndexNode(collectionIndexNode); ConvertCodeOfCollectionIndexNode(collectionIndexNode);
break; 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: // 类型定义 case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义
void ConvertCodeOfClassTypeDefinitionNode(ClassTypeDefinitionNode classTypeDefinitionNode) void ConvertCodeOfClassTypeDefinitionNode(ClassTypeDefinitionNode classTypeDefinitionNode)
{ {
@@ -417,8 +425,6 @@ namespace Serein.Script
ConvertCode(memberAssignmentNode.Object); ConvertCode(memberAssignmentNode.Object);
Append($".{memberAssignmentNode.MemberName} = "); Append($".{memberAssignmentNode.MemberName} = ");
ConvertCode(memberAssignmentNode.Value); ConvertCode(memberAssignmentNode.Value);
Append($";");
AppendLine(string.Empty);
} }
ConvertCodeOfMemberAssignmentNode(memberAssignmentNode); ConvertCodeOfMemberAssignmentNode(memberAssignmentNode);
break; break;
@@ -462,13 +468,13 @@ namespace Serein.Script
} }
var funcName = functionCallNode.FunctionName switch var funcName = functionCallNode.FunctionName switch
{ {
"int" => "@int" , "int" => "@int",
"bool" => "@bool" , "bool" => "@bool",
"double" => "@double" , "double" => "@double",
"long" => "@long" , "long" => "@long",
"decimal" => "@decimal" , "decimal" => "@decimal",
"float" => "@float" , "float" => "@float",
"byte" => "@byte" , "byte" => "@byte",
_ => functionCallNode.FunctionName, _ => functionCallNode.FunctionName,
}; };
@@ -495,6 +501,9 @@ namespace Serein.Script
} }
} }
} }

View File

@@ -1,4 +1,5 @@
using Serein.Library; using Serein.Library;
using Serein.Library.Api;
using Serein.Library.Utils; using Serein.Library.Utils;
using Serein.Script.Node; using Serein.Script.Node;
using Serein.Script.Node.FlowControl; using Serein.Script.Node.FlowControl;
@@ -105,10 +106,20 @@ namespace Serein.Script
case ReturnNode returnNode: // 程序退出节点 case ReturnNode returnNode: // 程序退出节点
Type AnalysisReturnNode(ReturnNode returnNode) Type AnalysisReturnNode(ReturnNode returnNode)
{ {
var resultType = Analysis(returnNode.Value); if(returnNode.Value is null)
NodeSymbolInfos[returnNode.Value] = resultType; {
NodeSymbolInfos[returnNode] = resultType; var resultType = typeof(void);
return resultType; NodeSymbolInfos[returnNode] = resultType;
return resultType;
}
else
{
var resultType = Analysis(returnNode.Value);
NodeSymbolInfos[returnNode.Value] = resultType;
NodeSymbolInfos[returnNode] = resultType;
return resultType;
}
} }
return AnalysisReturnNode(returnNode); return AnalysisReturnNode(returnNode);
case NullNode nullNode: // null case NullNode nullNode: // null
@@ -406,9 +417,25 @@ namespace Serein.Script
{ {
var objectType = Analysis(memberFunctionCallNode.Object); var objectType = Analysis(memberFunctionCallNode.Object);
var types = memberFunctionCallNode.Arguments.Select(arg => Analysis(arg)).ToArray(); var types = memberFunctionCallNode.Arguments.Select(arg => Analysis(arg)).ToArray();
var methodInfo = objectType.GetMethod(memberFunctionCallNode.FunctionName, types); var methodInfo = objectType.GetMethod(memberFunctionCallNode.FunctionName, types);
if (methodInfo is null) 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++) for (int index = 0; index < memberFunctionCallNode.Arguments.Count; index++)
{ {
ASTNode argNode = memberFunctionCallNode.Arguments[index]; ASTNode argNode = memberFunctionCallNode.Arguments[index];
@@ -428,7 +455,17 @@ namespace Serein.Script
case FunctionCallNode functionCallNode: // 外部挂载的函数调用 case FunctionCallNode functionCallNode: // 外部挂载的函数调用
Type AnalysisFunctionCallNode(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}"); throw new Exception($"脚本没有挂载方法 {functionCallNode.FunctionName}");
} }

View File

@@ -1281,7 +1281,7 @@ namespace Serein.Workbench.Views
private ContextMenu ConfiguerSelectionRectangle() private ContextMenu ConfiguerSelectionRectangle()
{ {
var contextMenu = new ContextMenu(); var contextMenu = new ContextMenu();
contextMenu.Items.Add(WpfFuncTool.CreateMenuItem("删除", (s, e) => /*contextMenu.Items.Add(WpfFuncTool.CreateMenuItem("删除", (s, e) =>
{ {
if (selectNodeControls.Count > 0) if (selectNodeControls.Count > 0)
{ {
@@ -1296,7 +1296,7 @@ namespace Serein.Workbench.Views
} }
} }
SelectionRectangle.Visibility = Visibility.Collapsed; SelectionRectangle.Visibility = Visibility.Collapsed;
})); }));*/
return contextMenu; return contextMenu;
// nodeControl.ContextMenu = contextMenu; // nodeControl.ContextMenu = contextMenu;
} }