diff --git a/Library/Api/IFlipflopContext.cs b/Library/Api/IFlipflopContext.cs
index 5931213..8c83b5c 100644
--- a/Library/Api/IFlipflopContext.cs
+++ b/Library/Api/IFlipflopContext.cs
@@ -15,10 +15,12 @@ namespace Serein.Library.Api
/// 触发器完成的状态(根据业务场景手动设置)
///
FlipflopStateType State { get; set; }
+
///
/// 触发类型
///
TriggerDescription Type { get; set; }
+
///
/// 触发时传递的数据
///
diff --git a/Library/Api/IFlowContext.cs b/Library/Api/IFlowContext.cs
index 3f2ffaa..5dc0344 100644
--- a/Library/Api/IFlowContext.cs
+++ b/Library/Api/IFlowContext.cs
@@ -14,16 +14,22 @@ namespace Serein.Library.Api
///
public interface IFlowContext
{
+ ///
+ /// 标识流程
+ ///
+ string Guid {get; }
+
///
/// 是否记录流程信息
///
bool IsRecordInvokeInfo { get; set; }
-
///
- /// 标识流程
+ /// 用于同一个流程上下文中共享、存储任意数据
+ /// 流程完毕时,如果存储的对象实现了 IDisposable 接口,将会自动调用
+ /// 谨慎使用,注意数据的生命周期和内存管理
///
- string Guid {get; }
+ object? Tag { get; set; }
///
/// 运行环境
diff --git a/Library/Api/IFlowEnvironment.cs b/Library/Api/IFlowEnvironment.cs
index 6ce4008..12e946a 100644
--- a/Library/Api/IFlowEnvironment.cs
+++ b/Library/Api/IFlowEnvironment.cs
@@ -1012,7 +1012,6 @@ namespace Serein.Library.Api
void SetUIContextOperation(UIContextOperation uiContextOperation);
#endregion
-
#region 项目相关操作
///
@@ -1068,7 +1067,6 @@ namespace Serein.Library.Api
bool TryGetDelegateDetails(string assemblyName, string methodName, out DelegateDetails del);
#endregion
-
#region 类库依赖相关
///
@@ -1099,8 +1097,6 @@ namespace Serein.Library.Api
#endregion
-
-
#region 远程相关
/*///
/// 启动远程服务
@@ -1142,8 +1138,6 @@ namespace Serein.Library.Api
#endregion
-
-
#region 节点中断、表达式(暂时没用)
#if false
diff --git a/Library/Ex/FlipflopException.cs b/Library/Ex/FlipflopException.cs
index 94a5747..963a2c3 100644
--- a/Library/Ex/FlipflopException.cs
+++ b/Library/Ex/FlipflopException.cs
@@ -37,7 +37,7 @@ namespace Serein.Library
///
///
///
- public FlipflopException(string message, bool isCancel = true,CancelClass clsss = CancelClass.CancelBranch) :base(message)
+ public FlipflopException(string message, bool isCancel = true, CancelClass clsss = CancelClass.CancelBranch) :base(message)
{
IsCancel = isCancel;
Type = clsss;
diff --git a/Library/FlowNode/FlowContext.cs b/Library/FlowNode/FlowContext.cs
index 9e48a7e..f5227a1 100644
--- a/Library/FlowNode/FlowContext.cs
+++ b/Library/FlowNode/FlowContext.cs
@@ -27,6 +27,14 @@ namespace Serein.Library
RunState = RunState.Running;
}
+ ///
+ /// 用于同一个流程上下文中共享、存储任意数据
+ /// 流程完毕时,如果存储的对象实现了 IDisposable 接口,将会自动调用
+ /// 谨慎使用,注意数据的生命周期和内存管理
+ ///
+ public object? Tag { get; set; }
+
+
///
/// 是否记录流程调用信息
///
@@ -78,7 +86,6 @@ namespace Serein.Library
private readonly ConcurrentDictionary> dictNodeParams = new ConcurrentDictionary>();
-
///
/// 记录流程调用信息
@@ -255,11 +262,15 @@ namespace Serein.Library
///
public void Reset()
{
+ if(Tag is IDisposable disposable)
+ {
+ disposable.Dispose(); // 释放 Tag 中的资源
+ }
this.dictNodeFlowData?.Clear();
ExceptionOfRuning = null;
+ flowInvokeInfos.Clear();
NextOrientation = ConnectionInvokeType.None;
RunState = RunState.Running;
- flowInvokeInfos.Clear();
Guid = global::System.Guid.NewGuid().ToString();
}
diff --git a/Library/ScriptBaseFunc.cs b/Library/ScriptBaseFunc.cs
index 25b782b..952e7c1 100644
--- a/Library/ScriptBaseFunc.cs
+++ b/Library/ScriptBaseFunc.cs
@@ -143,7 +143,7 @@ namespace Serein.Library
///
///
///
- public static IJsonToken json(string content)
+ public static IJsonToken jsonObj(string content)
{
/*if (string.IsNullOrWhiteSpace(content))
{
@@ -152,6 +152,20 @@ namespace Serein.Library
return JsonHelper.Parse(content);
}
+ ///
+ /// 转为JSON字符串
+ ///
+ ///
+ ///
+ public static string jsonStr(object data)
+ {
+ if (data is null)
+ {
+ return "{}";
+ }
+ return JsonHelper.Serialize(data);
+ }
+
#endregion
diff --git a/Library/Serein.Library.csproj b/Library/Serein.Library.csproj
index 3942ca7..33995fb 100644
--- a/Library/Serein.Library.csproj
+++ b/Library/Serein.Library.csproj
@@ -55,11 +55,15 @@
+
+
+
+
diff --git a/Library/Utils/TypeHelper.cs b/Library/Utils/TypeHelper.cs
index 063cead..42c326d 100644
--- a/Library/Utils/TypeHelper.cs
+++ b/Library/Utils/TypeHelper.cs
@@ -70,7 +70,6 @@ namespace Serein.Library.Utils
};
-
///
/// 字面量转为对应类型
///
@@ -84,11 +83,13 @@ namespace Serein.Library.Utils
return Type.GetType(valueStr);
}
+ #region 常见值类型
if (valueStr.Equals("bool", StringComparison.OrdinalIgnoreCase))
{
return typeof(bool);
}
+
#region 整数型
else if (valueStr.Equals("sbyte", StringComparison.OrdinalIgnoreCase)
|| valueStr.Equals(nameof(SByte), StringComparison.OrdinalIgnoreCase))
@@ -167,6 +168,170 @@ namespace Serein.Library.Utils
}
#endregion
+
+ #endregion
+
+ #region Array数组类型
+ if (valueStr.Equals("bool" + "[]", StringComparison.OrdinalIgnoreCase))
+ {
+ return typeof(bool[]);
+ }
+ #region 整数型
+ else if (valueStr.Equals("sbyte" + "[]", StringComparison.OrdinalIgnoreCase)
+ || valueStr.Equals(nameof(SByte) + "[]", StringComparison.OrdinalIgnoreCase))
+ {
+ return typeof(SByte[]);
+ }
+ else if (valueStr.Equals("short" + "[]", StringComparison.OrdinalIgnoreCase)
+ || valueStr.Equals(nameof(Int16) + "[]", StringComparison.OrdinalIgnoreCase))
+ {
+ return typeof(Int16[]);
+ }
+ else if (valueStr.Equals("int" + "[]", StringComparison.OrdinalIgnoreCase)
+ || valueStr.Equals(nameof(Int32) + "[]", StringComparison.OrdinalIgnoreCase))
+ {
+ return typeof(Int32[]);
+ }
+ else if (valueStr.Equals("long" + "[]", StringComparison.OrdinalIgnoreCase)
+ || valueStr.Equals(nameof(Int64) + "[]", StringComparison.OrdinalIgnoreCase))
+ {
+ return typeof(Int64[]);
+ }
+
+ else if (valueStr.Equals("byte" + "[]", StringComparison.OrdinalIgnoreCase)
+ || valueStr.Equals(nameof(Byte) + "[]", StringComparison.OrdinalIgnoreCase))
+ {
+ return typeof(Byte[]);
+ }
+ else if (valueStr.Equals("ushort" + "[]", StringComparison.OrdinalIgnoreCase)
+ || valueStr.Equals(nameof(UInt16) + "[]", StringComparison.OrdinalIgnoreCase))
+ {
+ return typeof(UInt16[]);
+ }
+ else if (valueStr.Equals("uint" + "[]", StringComparison.OrdinalIgnoreCase)
+ || valueStr.Equals(nameof(UInt32) + "[]", StringComparison.OrdinalIgnoreCase))
+ {
+ return typeof(UInt32[]);
+ }
+ else if (valueStr.Equals("ulong" + "[]", StringComparison.OrdinalIgnoreCase)
+ || valueStr.Equals(nameof(UInt64) + "[]", StringComparison.OrdinalIgnoreCase))
+ {
+ return typeof(UInt64[]);
+ }
+ #endregion
+
+ #region 浮点型
+ else if (valueStr.Equals("float" + "[]", StringComparison.OrdinalIgnoreCase)
+ || valueStr.Equals(nameof(Single) + "[]", StringComparison.OrdinalIgnoreCase))
+ {
+ return typeof(Single[]);
+ }
+ else if (valueStr.Equals("double" + "[]", StringComparison.OrdinalIgnoreCase)
+ || valueStr.Equals(nameof(Double) + "[]", StringComparison.OrdinalIgnoreCase))
+ {
+ return typeof(Double[]);
+ }
+ #endregion
+
+ #region 小数型
+
+ else if (valueStr.Equals("decimal" + "[]", StringComparison.OrdinalIgnoreCase)
+ || valueStr.Equals(nameof(Decimal) + "[]", StringComparison.OrdinalIgnoreCase))
+ {
+ return typeof(Decimal[]);
+ }
+ #endregion
+
+ #region 其他常见的类型
+ else if (valueStr.Equals(nameof(String) + "[]", StringComparison.OrdinalIgnoreCase))
+ {
+ return typeof(String[]);
+ }
+ #endregion
+ #endregion
+
+ #region List<> 数组类型
+ if (valueStr.Equals("list", StringComparison.OrdinalIgnoreCase))
+ {
+ return typeof(List);
+ }
+
+ #region 整数型
+ else if (valueStr.Equals("list", StringComparison.OrdinalIgnoreCase)
+ || valueStr.Equals(nameof(List), StringComparison.OrdinalIgnoreCase))
+ {
+ return typeof(List);
+ }
+ else if (valueStr.Equals("list", StringComparison.OrdinalIgnoreCase)
+ || valueStr.Equals(nameof(List), StringComparison.OrdinalIgnoreCase))
+ {
+ return typeof(List);
+ }
+ else if (valueStr.Equals("list", StringComparison.OrdinalIgnoreCase)
+ || valueStr.Equals(nameof(List), StringComparison.OrdinalIgnoreCase))
+ {
+ return typeof(List);
+ }
+ else if (valueStr.Equals("list", StringComparison.OrdinalIgnoreCase)
+ || valueStr.Equals(nameof(List), StringComparison.OrdinalIgnoreCase))
+ {
+ return typeof(List);
+ }
+
+ else if (valueStr.Equals("list", StringComparison.OrdinalIgnoreCase)
+ || valueStr.Equals(nameof(List), StringComparison.OrdinalIgnoreCase))
+ {
+ return typeof(List);
+ }
+ else if (valueStr.Equals("list", StringComparison.OrdinalIgnoreCase)
+ || valueStr.Equals(nameof(List), StringComparison.OrdinalIgnoreCase))
+ {
+ return typeof(List);
+ }
+ else if (valueStr.Equals("list", StringComparison.OrdinalIgnoreCase)
+ || valueStr.Equals(nameof(List), StringComparison.OrdinalIgnoreCase))
+ {
+ return typeof(List);
+ }
+ else if (valueStr.Equals("list", StringComparison.OrdinalIgnoreCase)
+ || valueStr.Equals(nameof(List), StringComparison.OrdinalIgnoreCase))
+ {
+ return typeof(List);
+ }
+ #endregion
+
+ #region 浮点型
+ else if (valueStr.Equals("list", StringComparison.OrdinalIgnoreCase)
+ || valueStr.Equals(nameof(List), StringComparison.OrdinalIgnoreCase))
+ {
+ return typeof(List);
+ }
+ else if (valueStr.Equals("list", StringComparison.OrdinalIgnoreCase)
+ || valueStr.Equals(nameof(List), StringComparison.OrdinalIgnoreCase))
+ {
+ return typeof(List);
+ }
+ #endregion
+
+ #region 小数型
+
+ else if (valueStr.Equals("list", StringComparison.OrdinalIgnoreCase)
+ || valueStr.Equals(nameof(List), StringComparison.OrdinalIgnoreCase))
+ {
+ return typeof(List);
+ }
+ #endregion
+
+ #region 其他常见的类型
+
+ else if (valueStr.Equals(nameof(List), StringComparison.OrdinalIgnoreCase))
+ {
+ return typeof(List);
+ }
+ #endregion
+
+ #endregion
+
else
{
throw new ArgumentException($"无法解析的字面量类型[{valueStr}]");
diff --git a/NodeFlow/Env/FlowEdit.cs b/NodeFlow/Env/FlowEdit.cs
index 088e4be..26cad00 100644
--- a/NodeFlow/Env/FlowEdit.cs
+++ b/NodeFlow/Env/FlowEdit.cs
@@ -48,8 +48,6 @@ namespace Serein.NodeFlow.Env
private readonly FlowLibraryService flowLibraryManagement;
private readonly FlowOperationService flowOperationService;
private readonly FlowModelService flowModelService;
- //private readonly NodeMVVMService nodeMVVMService;
-
///
/// 注册基本节点类型
@@ -633,33 +631,31 @@ namespace Serein.NodeFlow.Env
}
- /* var nodeModels = flowModelService.GetAllNodeModel();
- foreach (var toNode in nodeModels)
- {
- var canvasGuid = toNode.CanvasDetails.Guid;
- if (toNode.MethodDetails.ParameterDetailss == null)
- {
- continue;
- }
- for (var i = 0; i < toNode.MethodDetails.ParameterDetailss.Length; i++)
- {
- var pd = toNode.MethodDetails.ParameterDetailss[i];
- if (!string.IsNullOrEmpty(pd.ArgDataSourceNodeGuid)
- && TryGetNodeModel(pd.ArgDataSourceNodeGuid, out var fromNode))
- {
- *//*if (fromNode.NeedResultNodes[pd.ArgDataSourceType].Contains(toNode)
- && pd.ArgDataSourceNodeGuid == fromNode.Guid
- && )
- {
- continue;
- }*//*
- ConnectArgSourceNode(canvasGuid, fromNode.Guid, toNode.Guid, JunctionType.ReturnData, JunctionType.ArgData, pd.ArgDataSourceType, pd.Index);
- }
- }
- }*/
+ /* var nodeModels = flowModelService.GetAllNodeModel();
+ foreach (var toNode in nodeModels)
+ {
+ var canvasGuid = toNode.CanvasDetails.Guid;
+ if (toNode.MethodDetails.ParameterDetailss == null)
+ {
+ continue;
+ }
+ for (var i = 0; i < toNode.MethodDetails.ParameterDetailss.Length; i++)
+ {
+ var pd = toNode.MethodDetails.ParameterDetailss[i];
+ if (!string.IsNullOrEmpty(pd.ArgDataSourceNodeGuid)
+ && TryGetNodeModel(pd.ArgDataSourceNodeGuid, out var fromNode))
+ {
+ *//*if (fromNode.NeedResultNodes[pd.ArgDataSourceType].Contains(toNode)
+ && pd.ArgDataSourceNodeGuid == fromNode.Guid
+ && )
+ {
+ continue;
+ }*//*
+ ConnectArgSourceNode(canvasGuid, fromNode.Guid, toNode.Guid, JunctionType.ReturnData, JunctionType.ArgData, pd.ArgDataSourceType, pd.Index);
+ }
+ }
+ }*/
#endregion
-
-
}
#endregion
diff --git a/NodeFlow/Env/LocalFlowEnvironment.cs b/NodeFlow/Env/LocalFlowEnvironment.cs
index c9e6049..7577f4f 100644
--- a/NodeFlow/Env/LocalFlowEnvironment.cs
+++ b/NodeFlow/Env/LocalFlowEnvironment.cs
@@ -339,9 +339,14 @@ namespace Serein.NodeFlow.Env
var projectData = new SereinProjectData()
{
Librarys = this._flowLibraryService.GetAllLibraryInfo().ToArray(),
- Nodes = _flowModelService.GetAllNodeModel().Select(node => node.ToInfo()).Where(info => info is not null).ToArray(),
- Canvass = _flowModelService.GetAllCanvasModel().Select(canvas => canvas.ToInfo()).ToArray(),
- //StartNode = NodeModels.Values.FirstOrDefault(it => it.IsStart)?.Guid,
+ Nodes = _flowModelService.GetAllNodeModel()
+ .Select(node => node.ToInfo())
+ .Where(info => info is not null)
+ .ToArray(),
+ Canvass = _flowModelService.GetAllCanvasModel()
+ .Where(canvas => canvas.Nodes.Count != 0 && !"Default".Equals(canvas.Name))
+ .Select(canvas => canvas.ToInfo())
+ .ToArray(),
};
return projectData;
diff --git a/NodeFlow/FlowNodeExtension.cs b/NodeFlow/FlowNodeExtension.cs
index f880a2d..68bccb3 100644
--- a/NodeFlow/FlowNodeExtension.cs
+++ b/NodeFlow/FlowNodeExtension.cs
@@ -110,7 +110,7 @@ namespace Serein.NodeFlow
- ///
+ /*///
/// 触发器运行后状态转为对应的后继分支类别
///
///
@@ -126,7 +126,7 @@ namespace Serein.NodeFlow
FlipflopStateType.Cancel => ConnectionInvokeType.None,
_ => throw new NotImplementedException("未定义的流程状态")
};
- }
+ }*/
diff --git a/NodeFlow/Model/Nodes/SingleFlipflopNode.cs b/NodeFlow/Model/Nodes/SingleFlipflopNode.cs
index e39422e..00be761 100644
--- a/NodeFlow/Model/Nodes/SingleFlipflopNode.cs
+++ b/NodeFlow/Model/Nodes/SingleFlipflopNode.cs
@@ -72,23 +72,12 @@ namespace Serein.NodeFlow.Model.Nodes
instance = ioc.Get(md.ActingInstanceType);
}
- var args = MethodDetails.ParameterDetailss.Length == 0 ? [] : await this.GetParametersAsync(context, token);
+ var args = MethodDetails.ParameterDetailss.Length == 0 ? []
+ : await this.GetParametersAsync(context, token);
- // 因为这里会返回不确定的泛型 IFlipflopContext
- // 而我们只需要获取到 State 和 Value(返回的数据)
- // 所以使用 dynamic 类型接收
- dynamic flipflopContext = await dd.InvokeAsync(instance, args);
- FlipflopStateType flipflopStateType = flipflopContext.State;
- context.NextOrientation = flipflopStateType.ToContentType();
-
-
- if (flipflopContext.Type == TriggerDescription.Overtime)
- {
- throw new FlipflopException(MethodDetails.MethodName + "触发器超时触发。Guid" + Guid);
- }
- object result = flipflopContext.Value;
- var flowReslt = FlowResult.OK(this.Guid, context, result);
- return flowReslt;
+ var result = await dd.InvokeAsync(instance, args);
+ var flowResult = FlowResult.OK(this.Guid, context, result);
+ return flowResult;
}
}
diff --git a/NodeFlow/Tool/FlowWorkManagement.cs b/NodeFlow/Tool/FlowWorkManagement.cs
index a64bb70..a823be9 100644
--- a/NodeFlow/Tool/FlowWorkManagement.cs
+++ b/NodeFlow/Tool/FlowWorkManagement.cs
@@ -409,16 +409,6 @@ namespace Serein.NodeFlow.Services
continue;
}
await CallSuccessorNodesAsync(flipflopNode, token, pool, context);
- /*if (flipflopNode.IsWaitSuccessorNodes)
- {
- _ = Task.Run(async () => await CallSuccessorNodesAsync(flipflopNode, token, pool, context));
- }
- else
- {
- await CallSuccessorNodesAsync(flipflopNode, token, pool, context);
- }*/
-
-
}
catch (FlipflopException ex)
{
diff --git a/NodeFlow/Tool/NodeMethodDetailsHelper.cs b/NodeFlow/Tool/NodeMethodDetailsHelper.cs
index 9ec2a74..b0450f7 100644
--- a/NodeFlow/Tool/NodeMethodDetailsHelper.cs
+++ b/NodeFlow/Tool/NodeMethodDetailsHelper.cs
@@ -103,20 +103,34 @@ public static class NodeMethodDetailsHelper
if (methodInfo.ReturnType.IsGenericType && methodInfo.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
{
// 获取 Task<> 的泛型参数类型
- var innerType = methodInfo.ReturnType.GetGenericArguments()[0];
- if (innerType.IsGenericType && innerType.GetGenericTypeDefinition() == typeof(IFlipflopContext<>))
+ var innerTypes = methodInfo.ReturnType.GetGenericArguments();
+ if(innerTypes.Length == 1)
{
- var flipflopType = innerType.GetGenericArguments()[0];
- returnType = flipflopType;
+ var innerType = innerTypes[0];
+ returnType = innerType;
}
else
{
- SereinEnv.WriteLine(InfoType.WARN, $"[{methodName}]跳过创建,返回类型非预期的Task>。");
+ SereinEnv.WriteLine(InfoType.WARN, $"[{methodName}]跳过创建,返回类型非预期的Task。");
outMethodInfo = null;
methodDetails = null;
delegateDetails = null;
return false;
}
+ //var innerType = methodInfo.ReturnType.GetGenericArguments()[0];
+ //if (innerType.IsGenericType && innerType.GetGenericTypeDefinition() == typeof(IFlipflopContext<>))
+ //{
+ // var flipflopType = innerType.GetGenericArguments()[0];
+ // returnType = flipflopType;
+ //}
+ //else
+ //{
+ // SereinEnv.WriteLine(InfoType.WARN, $"[{methodName}]跳过创建,返回类型非预期的Task>。");
+ // outMethodInfo = null;
+ // methodDetails = null;
+ // delegateDetails = null;
+ // return false;
+ //}
}
else
{
diff --git a/Serein.Script/Node/ValueNode/BooleanNode.cs b/Serein.Script/Node/ValueNode/BooleanNode.cs
index c41d133..19c3cf8 100644
--- a/Serein.Script/Node/ValueNode/BooleanNode.cs
+++ b/Serein.Script/Node/ValueNode/BooleanNode.cs
@@ -9,14 +9,7 @@ namespace Serein.Script.Node
///
/// 布尔字面量
///
- public class BooleanNode : ASTNode
+ public class BooleanNode(bool value) : ValueNode(value)
{
- public bool Value { get; }
- public BooleanNode(bool value) => Value = value;
-
- public override string ToString()
- {
- return $"{Value}";
- }
}
}
diff --git a/Serein.Script/Node/ValueNode/CharNode.cs b/Serein.Script/Node/ValueNode/CharNode.cs
index b717d25..6a37f6b 100644
--- a/Serein.Script/Node/ValueNode/CharNode.cs
+++ b/Serein.Script/Node/ValueNode/CharNode.cs
@@ -6,16 +6,7 @@ using System.Threading.Tasks;
namespace Serein.Script.Node
{
- internal class CharNode : ASTNode
+ internal class CharNode(char value) : ValueNode(value)
{
- public char Value { get; }
- public CharNode(string value)
- {
- Value = char.Parse(value);
- }
- public override string ToString()
- {
- return $"'{Value}'";
- }
}
}
diff --git a/Serein.Script/Node/ValueNode/NumberNode.cs b/Serein.Script/Node/ValueNode/NumberNode.cs
index 13fc133..55b6dce 100644
--- a/Serein.Script/Node/ValueNode/NumberNode.cs
+++ b/Serein.Script/Node/ValueNode/NumberNode.cs
@@ -9,15 +9,9 @@ namespace Serein.Script.Node
///
/// 数值型节点
///
- public abstract class NumberNode : ASTNode where T : struct, IComparable
+ public abstract class NumberNode : ValueNode where T : struct, IComparable
{
- public T Value { get; }
public NumberNode(T value) => Value = value;
-
- public override string ToString()
- {
- return $"{Value}";
- }
}
diff --git a/Serein.Script/Node/ValueNode/RawStringNode.cs b/Serein.Script/Node/ValueNode/RawStringNode.cs
new file mode 100644
index 0000000..883305d
--- /dev/null
+++ b/Serein.Script/Node/ValueNode/RawStringNode.cs
@@ -0,0 +1,8 @@
+namespace Serein.Script.Node
+{
+ public class RawStringNode(string value) : ValueNode(value)
+ {
+ }
+
+
+}
diff --git a/Serein.Script/Node/ValueNode/StringNode.cs b/Serein.Script/Node/ValueNode/StringNode.cs
index 7e310ea..1b99678 100644
--- a/Serein.Script/Node/ValueNode/StringNode.cs
+++ b/Serein.Script/Node/ValueNode/StringNode.cs
@@ -9,11 +9,9 @@ namespace Serein.Script.Node
///
/// 字符串字面量节点
///
- public class StringNode : ASTNode
+ public class StringNode : ValueNode
{
- public string Value { get; }
-
- public StringNode(string input)
+ public StringNode(string input) : base()
{
// 使用 StringBuilder 来构建输出
StringBuilder output = new StringBuilder(input.Length);
@@ -59,11 +57,6 @@ namespace Serein.Script.Node
}
Value = output.ToString();
}
-
- public override string ToString()
- {
- return $"\"{Value}\"";
- }
}
diff --git a/Serein.Script/Node/ValueNode/ValueNode.cs b/Serein.Script/Node/ValueNode/ValueNode.cs
new file mode 100644
index 0000000..b509400
--- /dev/null
+++ b/Serein.Script/Node/ValueNode/ValueNode.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Serein.Script.Node
+{
+ public class ValueNode : ASTNode
+ {
+ public T Value { get; protected set; }
+
+ public ValueNode()
+ {
+
+ }
+ public ValueNode(T value)
+ {
+ this.Value = value;
+ }
+ public override string ToString()
+ {
+ return $"{Value}";
+ }
+ }
+}
diff --git a/Serein.Script/SereinScriptInterpreter.cs b/Serein.Script/SereinScriptInterpreter.cs
index a381f85..139d6a7 100644
--- a/Serein.Script/SereinScriptInterpreter.cs
+++ b/Serein.Script/SereinScriptInterpreter.cs
@@ -56,6 +56,8 @@ namespace Serein.Script
return null; // 返回 null
case CharNode charNode: // char字面量
return charNode.Value; // 返回字符值
+ case RawStringNode rawStringNode:
+ return rawStringNode.Value; // 返回原始字符串值
case StringNode stringNode: // 字符串字面量
return stringNode.Value; // 返回字符串值
case BooleanNode booleanNode: // 布尔值字面量
diff --git a/Serein.Script/SereinScriptLexer.cs b/Serein.Script/SereinScriptLexer.cs
index 2eb2363..dca7162 100644
--- a/Serein.Script/SereinScriptLexer.cs
+++ b/Serein.Script/SereinScriptLexer.cs
@@ -1,4 +1,7 @@
-namespace Serein.Script
+using System.Data.Common;
+using System.Numerics;
+
+namespace Serein.Script
{
///
/// Serein脚本词法分析器的Token类型
@@ -38,6 +41,10 @@
///
String,
///
+ /// 原始字符串(多行字符串)
+ ///
+ RawString,
+ ///
/// Char字符
///
Char,
@@ -217,7 +224,7 @@
if (_input[_index + 1] == '"'
&& _input[_index + 2] == '"')
{
- var value = _input.Slice(_index, 4).ToString();
+ //var value = _input.Slice(_index, 4).ToString();
// 原始字符串
return ReadRawString();
@@ -450,27 +457,38 @@
private Token ReadRawString()
{
- // skip opening triple quotes
- _index += 3;
-
- var start = _index;
- while (_index + 2 < _input.Length)
+ int startLine = _row;
+ _index += 3; // 跳过开头 """
+ int index = _index;
+ var contentStart = index;
+ while (index + 2 < _input.Length)
{
- if (_input[_index] == '"' && _input[_index + 1] == '"' && _input[_index + 2] == '"')
+ char current = _input[index];
+
+ // 行号处理
+ if (current == '\n')
{
- var value = _input.Slice(start, _index - start).ToString();
- _index += 3; // skip closing """
- return CreateToken(TokenType.String, value);
+ _row++;
+ }
+
+ // 检查是否是结束符 """
+ if (_input[index] != '"' || _input[index + 1] != '"' || _input[index + 2] != '"')
+ {
+ index++;
+ }
+ else
+ {
+ var value = _input.Slice(contentStart, index - contentStart).ToString();
+ _index += 3;
+ // 构建带行号信息的 Token(假设 Token 有 StartLine 属性)
+ return CreateToken(TokenType.RawString, value);
}
- _index++;
}
- throw new Exception("Unterminated raw string literal");
-
+ throw new Exception($"Unterminated raw string literal starting at line {startLine}");
}
-
///
/// 读取硬编码的文本
///
diff --git a/Serein.Script/SereinScriptParser.cs b/Serein.Script/SereinScriptParser.cs
index 1afdac2..c90ab49 100644
--- a/Serein.Script/SereinScriptParser.cs
+++ b/Serein.Script/SereinScriptParser.cs
@@ -112,9 +112,9 @@ namespace Serein.Script
isAssignment = true;
break;
}
- if(peekCount > 19999)
+ if(peekCount > 3999)
{
- throw new Exception("解析异常,peek次数过多,请减少脚本代码");
+ throw new Exception("解析异常,peek次数过多,可能是解析器出了bug");
}
}
#endregion
@@ -122,16 +122,19 @@ namespace Serein.Script
#region 生成赋值语句/一般语句的ASTNode
if (isAssignment)
{
+
// 以赋值语句的形式进行处理
var assignmentNode = ParseAssignmentNode(); // 解析复制表达式
- NextToken();// 消耗 ";"
+ //if(_currentToken.Type == TokenType.Semicolon)
+ NextToken();// 消耗 ";"
return assignmentNode;
}
else
{
// 以一般语句的形式进行处理,可当作表达式进行解析
- var targetNode = ParserExpression();
- NextToken();// 消耗 ";"
+ var targetNode = ParserExpression();
+ //if (_currentToken.Type == TokenType.Semicolon)
+ NextToken();// 消耗 ";"
return targetNode;
}
#endregion
@@ -308,6 +311,7 @@ namespace Serein.Script
}
else
{
+ var c = _currentToken;
// 反转赋值。
NextToken(); // 消耗 "=" 并获取赋值语句的右值表达式。
ASTNode valueNode = ParserExpression();
@@ -515,6 +519,13 @@ namespace Serein.Script
fieldTypeName = $"{fieldTypeName}.{_currentToken.Value}"; // 向后扩充
continue;
}
+ else if (peekToken.Type == TokenType.SquareBracketsLeft)
+ {
+ NextToken(); // 消耗数组类型定义的 "["
+ NextToken(); // 消耗数组类型定义的 "]"
+ fieldTypeName += "[]";
+ continue;
+ }
else if (peekToken.Type == TokenType.Identifier)
{
// 尝试解析变量名称
@@ -677,7 +688,7 @@ namespace Serein.Script
}
else if (_currentToken.Type == TokenType.BraceRight)
{
- break;
+ continue;
}
}
else
@@ -1009,6 +1020,7 @@ namespace Serein.Script
if(peekToken.Type == TokenType.ParenthesisRight // 可能解析完了方法参数
|| peekToken.Type == TokenType.Comma // 可能解析完了方法参数
|| peekToken.Type == TokenType.Operator // 可能解析完了方法参数
+ || peekToken.Type == TokenType.BraceRight // 可能解析完了方法参数
|| peekToken.Type == TokenType.ParenthesisRight) // 可能解析完了下标索引
{
return source;
@@ -1065,6 +1077,13 @@ namespace Serein.Script
NextToken(); // 消耗布尔量
return new BooleanNode(value).SetTokenInfo(factorToken);
}
+ else if (_currentToken.Type == TokenType.RawString)
+ {
+ var value = _currentToken.Value;
+ NextToken(); // 消耗字符串
+ var node = new RawStringNode(value).SetTokenInfo(factorToken);
+ return node;
+ }
else if (_currentToken.Type == TokenType.String)
{
var value = _currentToken.Value;
@@ -1076,7 +1095,8 @@ namespace Serein.Script
{
var value = _currentToken.Value;
NextToken(); ; // 消耗Char
- return new CharNode(value).SetTokenInfo(factorToken);
+ var @char = char.Parse(value);
+ return new CharNode(@char).SetTokenInfo(factorToken);
}
else if (_currentToken.Type == TokenType.InterpolatedString)
{
@@ -1186,4 +1206,6 @@ namespace Serein.Script
}
+
+
}
diff --git a/Serein.Script/SereinScriptToCsharpScript.cs b/Serein.Script/SereinScriptToCsharpScript.cs
index 5673bcb..2a20dbc 100644
--- a/Serein.Script/SereinScriptToCsharpScript.cs
+++ b/Serein.Script/SereinScriptToCsharpScript.cs
@@ -167,7 +167,7 @@ namespace Serein.Script
});
return string.Join(',', values);
}
-
+
private void ConvertCode(ASTNode node)
{
switch (node)
@@ -198,6 +198,12 @@ namespace Serein.Script
case CharNode charNode: // char字面量
Append($"'{charNode.Value}'");
break;
+ case RawStringNode rawStringNode: // 原始字符串
+ AppendLine("");
+ Append("\"\"\"");
+ Append(rawStringNode.Value);
+ Append("\"\"\"");
+ break;
case StringNode stringNode: // 字符串字面量
Append($"\"{stringNode.Value}\"");
break;
@@ -502,9 +508,9 @@ namespace Serein.Script
}
-
-
}
}
+
+
diff --git a/Serein.Script/SereinScriptTypeAnalysis.cs b/Serein.Script/SereinScriptTypeAnalysis.cs
index adebee7..6fd60f7 100644
--- a/Serein.Script/SereinScriptTypeAnalysis.cs
+++ b/Serein.Script/SereinScriptTypeAnalysis.cs
@@ -128,6 +128,9 @@ namespace Serein.Script
case CharNode charNode: // char字面量
NodeSymbolInfos[charNode] = typeof(char);
return typeof(char);
+ case RawStringNode rawStringNode: // 原始字符串字面量(多行字符串)
+ NodeSymbolInfos[rawStringNode] = typeof(string);
+ return typeof(string);
case StringNode stringNode: // 字符串字面量
NodeSymbolInfos[stringNode] = typeof(string);
return typeof(string);
@@ -507,6 +510,7 @@ namespace Serein.Script
break;
case NullNode nullNode: // null
case CharNode charNode: // char字面量
+ case RawStringNode rawStringNode:
case StringNode stringNode: // 字符串字面量
case BooleanNode booleanNode: // 布尔值字面量
case NumberIntNode numberIntNode: // int整型数值字面量
@@ -558,6 +562,20 @@ namespace Serein.Script
}
AnalysisCollectionIndexNode(collectionIndexNode);
break;
+ case CollectionAssignmentNode collectionAssignmentNode: // 集合赋值操作
+ void AnalysisCollectionAssignmentNode(CollectionAssignmentNode collectionAssignmentNode)
+ {
+ Analysis(collectionAssignmentNode);
+ }
+ AnalysisCollectionAssignmentNode(collectionAssignmentNode);
+ break;
+ case ArrayDefintionNode arrayDefintionNode:
+ void AnalysisArrayDefintionNode(ArrayDefintionNode arrayDefintionNode)
+ {
+ Analysis(arrayDefintionNode);
+ }
+ AnalysisArrayDefintionNode(arrayDefintionNode);
+ break;
case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义
Analysis(classTypeDefinitionNode);
break;
diff --git a/Workbench/Test.cs b/Workbench/Test.cs
deleted file mode 100644
index b2fa14c..0000000
--- a/Workbench/Test.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Serein.Workbench
-{
- internal class Test
- {
- }
-}