diff --git a/Library/Utils/DynamicObjectHelper.cs b/Library/Utils/DynamicObjectHelper.cs
index 95a7c42..7d8d8ee 100644
--- a/Library/Utils/DynamicObjectHelper.cs
+++ b/Library/Utils/DynamicObjectHelper.cs
@@ -5,6 +5,7 @@ using System.Reflection.Emit;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
+using System.ComponentModel;
namespace Serein.Library.Utils
{
@@ -188,8 +189,142 @@ namespace Serein.Library.Utils
return dynamicType;
}
+ ///
+ /// 创建继承通知接口、具有属性的类型
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static Type CreateTypeWithINotifyPropertyChanged(IDictionary properties, string typeName, bool isOverlay = false)
+ {
+ if (typeCache.ContainsKey(typeName) && !isOverlay)
+ return typeCache[typeName];
+ var typeBuilder = ModuleBuilder.DefineType(typeName, TypeAttributes.Public | TypeAttributes.Class);
+ typeBuilder.AddInterfaceImplementation(typeof(INotifyPropertyChanged));
+ // 添加 PropertyChanged 字段
+ var eventHandlerType = typeof(PropertyChangedEventHandler);
+ var propertyChangedField = typeBuilder.DefineField("PropertyChanged", eventHandlerType, FieldAttributes.Private);
+
+ // 添加 PropertyChanged 事件
+ var eventBuilder = typeBuilder.DefineEvent("PropertyChanged", EventAttributes.None, eventHandlerType);
+
+ // add_PropertyChanged
+ var addMethod = typeBuilder.DefineMethod("add_PropertyChanged", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Virtual | MethodAttributes.HideBySig, null, new[] { eventHandlerType });
+ {
+
+ var il = addMethod.GetILGenerator();
+ var combine = typeof(Delegate).GetMethod("Combine", new[] { typeof(Delegate), typeof(Delegate) });
+
+ // this.PropertyChanged = (PropertyChangedEventHandler)Delegate.Combine(this.PropertyChanged, value);
+ il.Emit(OpCodes.Ldarg_0); // 加载 this(当前实例)到栈
+ il.Emit(OpCodes.Ldarg_0); // 再次加载 this,用于访问字段
+ il.Emit(OpCodes.Ldfld, propertyChangedField); // 加载 this.PropertyChanged 字段值
+ il.Emit(OpCodes.Ldarg_1); // 加载方法参数 value(订阅者委托)
+ il.Emit(OpCodes.Call, combine); // 调用 Delegate.Combine(a, b)
+ il.Emit(OpCodes.Castclass, eventHandlerType); // 强转回 PropertyChangedEventHandler 类型
+ il.Emit(OpCodes.Stfld, propertyChangedField); // 赋值给 this.PropertyChanged
+ il.Emit(OpCodes.Ret); // return
+ }
+
+ // remove_PropertyChanged
+ var removeMethod = typeBuilder.DefineMethod("remove_PropertyChanged", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Virtual | MethodAttributes.HideBySig, null, new[] { eventHandlerType });
+ {
+ var il = removeMethod.GetILGenerator();
+ var remove = typeof(Delegate).GetMethod("Remove", new[] { typeof(Delegate), typeof(Delegate) });
+
+ // this.PropertyChanged = (PropertyChangedEventHandler)Delegate.Remove(this.PropertyChanged, value);
+ il.Emit(OpCodes.Ldarg_0); // 加载 this
+ il.Emit(OpCodes.Ldarg_0); // 再次加载 this
+ il.Emit(OpCodes.Ldfld, propertyChangedField); // 加载字段 this.PropertyChanged
+ il.Emit(OpCodes.Ldarg_1); // 加载 value(要移除的委托)
+ il.Emit(OpCodes.Call, remove); // 调用 Delegate.Remove(a, b)
+ il.Emit(OpCodes.Castclass, eventHandlerType); // 转换为 PropertyChangedEventHandler
+ il.Emit(OpCodes.Stfld, propertyChangedField); // 设置 this.PropertyChanged = 结果
+ il.Emit(OpCodes.Ret); // return
+ }
+
+ eventBuilder.SetAddOnMethod(addMethod);
+ eventBuilder.SetRemoveOnMethod(removeMethod);
+
+ // 定义 OnPropertyChanged 方法
+ var onPropertyChangedMethod = typeBuilder.DefineMethod(
+ "OnPropertyChanged",
+ MethodAttributes.Private,
+ null,
+ new[] { typeof(string) });
+
+ {
+ var il = onPropertyChangedMethod.GetILGenerator();
+ var label = il.DefineLabel();
+
+ // if (PropertyChanged == null) return;
+ il.Emit(OpCodes.Ldarg_0); // 加载 this
+ il.Emit(OpCodes.Ldfld, propertyChangedField); // 加载 this.PropertyChanged
+ il.Emit(OpCodes.Brfalse_S, label); // 如果为空(null),跳转到 label,跳过通知调用
+
+ // PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ il.Emit(OpCodes.Ldarg_0); // 加载 this(委托调用目标)
+ il.Emit(OpCodes.Ldfld, propertyChangedField); // 加载 PropertyChanged 委托
+ il.Emit(OpCodes.Ldarg_0); // 加载 this 作为 sender 参数
+ il.Emit(OpCodes.Ldarg_1); // 加载 propertyName 参数(string)
+ il.Emit(OpCodes.Newobj, typeof(PropertyChangedEventArgs).GetConstructor(new[] { typeof(string) })); // 构造 new PropertyChangedEventArgs(propertyName)
+ il.Emit(OpCodes.Callvirt, typeof(PropertyChangedEventHandler).GetMethod("Invoke")); // 调用委托 Invoke(sender, args)
+ il.MarkLabel(label); // 跳转目标(如果委托为 null 则跳转至此)
+ il.Emit(OpCodes.Ret); // return
+ }
+
+ // 为每个属性生成字段 + get/set + OnPropertyChanged 调用
+ foreach (var kv in properties)
+ {
+ string propName = kv.Key;
+ Type propType = kv.Value ?? typeof(object);
+
+ var fieldBuilder = typeBuilder.DefineField("_" + propName, propType, FieldAttributes.Private);
+
+ var propertyBuilder = typeBuilder.DefineProperty(propName, PropertyAttributes.HasDefault, propType, null);
+
+ var getter = typeBuilder.DefineMethod("get_" + propName,
+ MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
+ propType, Type.EmptyTypes);
+
+ {
+ // get_PropertyName()
+ var il = getter.GetILGenerator();
+ il.Emit(OpCodes.Ldarg_0); // 加载 this
+ il.Emit(OpCodes.Ldfld, fieldBuilder); // 读取私有字段 _PropertyName
+ il.Emit(OpCodes.Ret); // 返回字段值
+ }
+
+ var setter = typeBuilder.DefineMethod("set_" + propName,
+ MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
+ null, new[] { propType });
+
+ {
+ // set_PropertyName(value)
+ var il = setter.GetILGenerator();
+ il.Emit(OpCodes.Ldarg_0); // 加载 this
+ il.Emit(OpCodes.Ldarg_1); // 加载 value 参数
+ il.Emit(OpCodes.Stfld, fieldBuilder); // 设置字段 _PropertyName = value
+
+ il.Emit(OpCodes.Ldarg_0); // 加载 this
+ il.Emit(OpCodes.Ldstr, propName); // 加载属性名字符串作为通知参数
+ il.Emit(OpCodes.Call, onPropertyChangedMethod); // 调用 OnPropertyChanged(propName)
+
+ il.Emit(OpCodes.Ret); // return
+ }
+
+ propertyBuilder.SetGetMethod(getter);
+ propertyBuilder.SetSetMethod(setter);
+ }
+
+ var dynamicType = typeBuilder.CreateType();
+ typeCache[typeName] = dynamicType;
+ return dynamicType;
+ }
#region 动态创建对象并赋值
// 方法 1: 创建动态类型及其对象实例
diff --git a/NodeFlow/Model/Node/SingleScriptNode.cs b/NodeFlow/Model/Node/SingleScriptNode.cs
index 0336c3b..66bec73 100644
--- a/NodeFlow/Model/Node/SingleScriptNode.cs
+++ b/NodeFlow/Model/Node/SingleScriptNode.cs
@@ -33,19 +33,20 @@ namespace Serein.NodeFlow.Model
///
public override bool IsBase => true;
- private IScriptFlowApi ScriptFlowApi;
- private ProgramNode programNode;
- private readonly SereinScriptInterpreter scriptInterpreter;
private bool IsScriptChanged = false;
+ ///
+ /// 脚本解释器
+ ///
+ private readonly SereinScript sereinScript;
+
///
/// 构建流程脚本节点
///
///
- public SingleScriptNode(IFlowEnvironment environment):base(environment)
+ public SingleScriptNode(IFlowEnvironment environment) : base(environment)
{
- ScriptFlowApi = new ScriptFlowApi(environment, this);
- scriptInterpreter = new SereinScriptInterpreter();
+ sereinScript = new SereinScript();
}
static SingleScriptNode()
@@ -60,7 +61,7 @@ namespace Serein.NodeFlow.Model
// 加载基础方法
foreach ((string name, MethodInfo method) item in tempMethods)
{
- SereinScriptInterpreter.AddStaticFunction(item.name, item.method);
+ SereinScript.AddStaticFunction(item.name, item.method);
}
}
@@ -157,24 +158,10 @@ namespace Serein.NodeFlow.Model
varNames.Add(pd.Name);
}
- /*var sb = new StringBuilder();
- foreach (var pd in MethodDetails.ParameterDetailss)
- {
- sb.AppendLine($"let {pd.Name};"); // 提前声明这些变量
- }
- sb.Append(Script);
- var script = sb.ToString();*/
- var parser = new SereinScriptParser(); // 准备解析器
- var typeAnalysis = new SereinScriptTypeAnalysis(); // 准备分析器
- programNode = parser.Parse(Script); // 开始解析获取程序主节点
+ Dictionary dict = MethodDetails.ParameterDetailss.ToDictionary(pd => pd.Name, pd => pd.DataType); // 准备预定义类型
- var dict = MethodDetails.ParameterDetailss.ToDictionary(pd => pd.Name, pd => pd.DataType);
- typeAnalysis.NodeSymbolInfos.Clear(); // 清空符号表
- typeAnalysis.LoadSymbol(dict); // 提前加载脚本节点定义的符号
- typeAnalysis.AnalysisProgramNode(programNode); // 分析节点类型
- var returnType = typeAnalysis.NodeSymbolInfos[programNode]; // 获取返回类型
+ var returnType = sereinScript.ParserScript(dict, Script); // 开始解析获取程序主节点
MethodDetails.ReturnType = returnType;
- //scriptInterpreter.SetTypeAnalysis(typeAnalysis); // 设置类型分析器
}
catch (Exception ex)
@@ -244,8 +231,7 @@ namespace Serein.NodeFlow.Model
if (token.IsCancellationRequested) return null;
-
- var result = await scriptInterpreter.InterpretAsync(scriptContext, programNode); // 从入口节点执行
+ var result = await sereinScript.InterpreterAsync(scriptContext); // 从入口节点执行
envEvent.FlowRunComplete -= onFlowStop;
return new FlowResult(this.Guid, context, result);
}
@@ -259,12 +245,7 @@ namespace Serein.NodeFlow.Model
private static class ScriptBaseFunc
{
- public static DateTime GetNow() => DateTime.Now;
-
- public static int Add(int Left, int Right)
- {
- return Left + Right;
- }
+ public static DateTime now() => DateTime.Now;
#region 常用的类型转换
public static bool @bool(object value)
@@ -321,6 +302,21 @@ namespace Serein.NodeFlow.Model
}
}
+ public static void regType(Type type, string name = "")
+ {
+ SereinScript.AddClassType(type, name);
+ }
+
+ public static string str(object obj)
+ {
+ return obj?.ToString() ?? string.Empty;
+ }
+
+ public static object obj(Type type)
+ {
+ return Activator.CreateInstance(type);
+ }
+
public static Type type(object type)
{
return type.GetType();
diff --git a/Serein.Script/Node/ClassTypeDefinitionNode.cs b/Serein.Script/Node/ClassTypeDefinitionNode.cs
index 543ec07..ab2e39c 100644
--- a/Serein.Script/Node/ClassTypeDefinitionNode.cs
+++ b/Serein.Script/Node/ClassTypeDefinitionNode.cs
@@ -15,41 +15,40 @@ namespace Serein.Script.Node
public bool IsOverlay { get; set; }
///
- /// 类名称
+ /// 类型名称
///
- public string ClassName { get; }
+ public TypeNode ClassType { get; }
///
- /// 字段名称及字段类型
+ /// 类型中的属性
///
- [Obsolete("此属性已经过时,将会改为Dictionary", false)]
- public Dictionary Fields { get; }
-
- ///
- /// 字段名称及字段类型(Kvp[fididName:fidleTypeName])
- ///
- public Dictionary FieldInfos { get; }
+ public Dictionary Propertys { get; }
- public ClassTypeDefinitionNode(Dictionary fields, string className)
+ public ClassTypeDefinitionNode(Dictionary propertys, TypeNode className)
{
- this.FieldInfos = fields;
- this.ClassName = className;
+ this.Propertys = propertys;
+ this.ClassType = className;
}
- [Obsolete("此构造方法已经过时,可能在下一个版本中移除", false)]
- public ClassTypeDefinitionNode(Dictionary fields, string className)
- {
- this.Fields = fields;
- this.ClassName = className;
- }
- [Obsolete("此构造方法已经过时,可能在下一个版本中移除", false)]
- public ClassTypeDefinitionNode(Dictionary fields, string className, bool isOverlay)
- {
- this.Fields = fields;
- this.ClassName = className;
- IsOverlay = isOverlay;
- }
+
+
+ /* ///
+ /// 字段名称及字段类型
+ ///
+ [Obsolete("此属性已经过时,将会改为Dictionary", false)]
+ public Dictionary Fields { get; }
+
+ */
+
+
+ /* ///
+ /// 字段名称及字段类型(Kvp[fididName:fidleTypeName])
+ ///
+ public Dictionary FieldInfos { get; }
+ */
+ //[Obsolete("此构造方法已经过时,可能在下一个版本中移除", false)]
+
}
}
diff --git a/Serein.Script/Node/CtorAssignmentNode.cs b/Serein.Script/Node/CtorAssignmentNode.cs
new file mode 100644
index 0000000..b8d8c52
--- /dev/null
+++ b/Serein.Script/Node/CtorAssignmentNode.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Serein.Script.Node
+{
+
+
+ ///
+ /// 构造器对对象成员赋值
+ ///
+ public class CtorAssignmentNode : ASTNode
+ {
+ ///
+ /// 成员来源类型
+ ///
+ public TypeNode Class { get; }
+
+ ///
+ /// 成员名称
+ ///
+ public string MemberName { get; }
+
+ ///
+ /// 值来源
+ ///
+ public ASTNode Value { get; }
+
+ ///
+ /// 构造器赋值
+ ///
+ /// 成员来源类型
+ /// 成员名称
+ /// 成员值来源
+ public CtorAssignmentNode(TypeNode typeNode, string memberName, ASTNode value)
+ {
+ Class = typeNode;
+ MemberName = memberName;
+ Value = value;
+ }
+
+
+ }
+}
diff --git a/Serein.Script/Node/ObjectInstantiationNode.cs b/Serein.Script/Node/ObjectInstantiationNode.cs
index bd5e301..1ee4dd0 100644
--- a/Serein.Script/Node/ObjectInstantiationNode.cs
+++ b/Serein.Script/Node/ObjectInstantiationNode.cs
@@ -12,19 +12,31 @@ namespace Serein.Script.Node
public class ObjectInstantiationNode : ASTNode
{
///
- /// 类型名称
+ /// 类型来源
///
- public string TypeName { get; }
+ public TypeNode Type { get; }
///
/// 构造方法的参数来源
///
public List Arguments { get; }
- public ObjectInstantiationNode(string typeName, List arguments)
+
+ ///
+ /// 构造器赋值
+ ///
+ public List CtorAssignments { get; private set; } = [];
+
+ public ObjectInstantiationNode(TypeNode type, List arguments)
{
- this.TypeName = typeName;
+ this.Type = type;
this.Arguments = arguments;
}
+
+ public ObjectInstantiationNode SetCtorAssignments(List ctorAssignments)
+ {
+ CtorAssignments = ctorAssignments;
+ return this;
+ }
}
}
diff --git a/Serein.Script/Node/TypeNode.cs b/Serein.Script/Node/TypeNode.cs
new file mode 100644
index 0000000..bb12ed4
--- /dev/null
+++ b/Serein.Script/Node/TypeNode.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Serein.Script.Node
+{
+ ///
+ /// 类型节点
+ ///
+ public class TypeNode : ASTNode
+ {
+ public string TypeName { get; }
+
+ public TypeNode(string typeName)
+ {
+ TypeName = typeName;
+ }
+
+ }
+}
diff --git a/Serein.Script/SereinScript.cs b/Serein.Script/SereinScript.cs
new file mode 100644
index 0000000..352c9c4
--- /dev/null
+++ b/Serein.Script/SereinScript.cs
@@ -0,0 +1,131 @@
+using Serein.Library;
+using Serein.Script.Node;
+using Serein.Script.Node.FlowControl;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Serein.Script
+{
+ public class SereinScript
+ {
+ ///
+ /// 类型分析
+ ///
+ public SereinScriptTypeAnalysis TypeAnalysis { get; set; } = new SereinScriptTypeAnalysis();
+
+
+
+ private ProgramNode? programNode;
+
+ public Type ParserScript(Dictionary argTypes, string script)
+ {
+ SereinScriptParser parser = new SereinScriptParser();
+ var programNode = parser.Parse(script);
+ TypeAnalysis.NodeSymbolInfos.Clear(); // 清空符号表
+ TypeAnalysis.LoadSymbol(argTypes); // 提前加载脚本节点定义的符号
+ TypeAnalysis.Analysis(programNode); // 分析节点类型
+ var returnType = TypeAnalysis.NodeSymbolInfos[programNode]; // 获取返回类型
+ this.programNode = programNode;
+ return returnType; // 脚本返回类型
+ }
+
+ public async Task