From fc05cd662b66eb89ddea8cf181b085a82d6b263b Mon Sep 17 00:00:00 2001 From: fengjiayi <12821976+ning_xi@user.noreply.gitee.com> Date: Fri, 18 Jul 2025 22:45:06 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E5=86=99=E4=BA=86Script=E7=9A=84?= =?UTF-8?q?=E8=A7=A3=E9=87=8A=E5=99=A8=E4=BB=A3=E7=A0=81=EF=BC=8C=E4=BD=BF?= =?UTF-8?q?=E5=85=B6=E6=9B=B4=E5=8A=A0=E7=9B=B4=E8=A7=82=E3=80=82=E9=87=8D?= =?UTF-8?q?=E5=86=99=E4=BA=86=E6=B5=81=E7=A8=8B=E6=8E=A7=E5=88=B6=E7=9A=84?= =?UTF-8?q?=E9=83=A8=E5=88=86=E4=BB=A3=E7=A0=81=EF=BC=8C=E5=88=86=E7=A6=BB?= =?UTF-8?q?=E8=BF=90=E8=A1=8C=E7=8E=AF=E5=A2=83IOC=E4=B8=8E=E6=B5=81?= =?UTF-8?q?=E7=A8=8BIOC=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Library/Api/IDynamicContext.cs | 3 +- Library/Api/IFlowControl.cs | 13 +- Library/Api/IFlowEnvironment.cs | 3 +- Library/FlowNode/DynamicContext.cs | 3 +- .../FlowNode/LightweightFlowEnvironment.cs | 9 +- Library/FlowNode/NodeDebugSetting.cs | 6 +- Library/FlowNode/ParameterDetails.cs | 4 +- Library/Utils/BenchmarkHelpers.cs | 1 + Library/Utils/EmitHelper.cs | 31 +- Library/Utils/LinqAsyncHelper.cs | 47 + Library/Utils/SereinIoc.cs | 4 +- .../LogicControl/ViewLogicControl.cs | 70 -- Net462DllTest/Net462DllTest.csproj | 22 - .../View/FromWorkBenchView.Designer.cs | 110 -- Net462DllTest/View/FromWorkBenchView.cs | 59 -- Net462DllTest/View/FromWorkBenchView.resx | 120 --- Net462DllTest/View/TestFormView.Designer.cs | 62 -- Net462DllTest/View/TestFormView.cs | 19 - Net462DllTest/View/TestFormView.resx | 120 --- .../ViewModel/FromWorkBenchViewModel.cs | 140 --- Net462DllTest/Web/PlcSocketService.cs | 21 +- NodeFlow/Env/FlowControl.cs | 54 +- NodeFlow/Env/FlowEdit.cs | 2 +- NodeFlow/FlowNodeExtension.cs | 12 +- NodeFlow/FlowWorkOptions.cs | 6 +- NodeFlow/Model/Node/NodeModelBaseFunc.cs | 6 +- NodeFlow/Model/Node/SingleFlipflopNode.cs | 6 +- NodeFlow/Model/Node/SingleFlowCallNode.cs | 4 + .../Model/Operation/CreateNodeOperation.cs | 6 +- NodeFlow/Services/FlowWorkManagement.cs | 19 +- Serein.Script/IScriptInvokeContext.cs | 4 +- Serein.Script/Node/AssignmentNode.cs | 5 +- Serein.Script/ScriptInvokeContext.cs | 2 +- Serein.Script/SereinSciptException.cs | 1 + Serein.Script/SereinScript.cs | 5 +- Serein.Script/SereinScriptInterpreter.cs | 981 +++++++----------- Serein.Script/SereinScriptLexer.cs | 2 - Serein.Script/SereinScriptTypeAnalysis.cs | 3 +- 38 files changed, 567 insertions(+), 1418 deletions(-) create mode 100644 Library/Utils/LinqAsyncHelper.cs delete mode 100644 Net462DllTest/LogicControl/ViewLogicControl.cs delete mode 100644 Net462DllTest/View/FromWorkBenchView.Designer.cs delete mode 100644 Net462DllTest/View/FromWorkBenchView.cs delete mode 100644 Net462DllTest/View/FromWorkBenchView.resx delete mode 100644 Net462DllTest/View/TestFormView.Designer.cs delete mode 100644 Net462DllTest/View/TestFormView.cs delete mode 100644 Net462DllTest/View/TestFormView.resx delete mode 100644 Net462DllTest/ViewModel/FromWorkBenchViewModel.cs diff --git a/Library/Api/IDynamicContext.cs b/Library/Api/IDynamicContext.cs index 4487eda..5fb69e7 100644 --- a/Library/Api/IDynamicContext.cs +++ b/Library/Api/IDynamicContext.cs @@ -17,10 +17,11 @@ namespace Serein.Library.Api string Guid {get; } /// - /// 运行环境,包含IOC容器。 + /// 运行环境 /// IFlowEnvironment Env { get; } + /// /// 是否正在运行 /// diff --git a/Library/Api/IFlowControl.cs b/Library/Api/IFlowControl.cs index cfdbf86..3031921 100644 --- a/Library/Api/IFlowControl.cs +++ b/Library/Api/IFlowControl.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Threading.Tasks; namespace Serein.Library.Api @@ -8,6 +9,13 @@ namespace Serein.Library.Api /// public interface IFlowControl { + + /// + /// 单例模式IOC容器,内部维护了一个实例字典,默认使用类型的FullName作为Key,如果以“接口-实现类”的方式注册,那么将使用接口类型的FullName作为Key。 + /// 当某个类型注册绑定成功后,将不会因为其它地方尝试注册相同类型的行为导致类型被重新创建。 + /// + ISereinIOC IOC { get; } + /// /// 需要你提供一个由你实现的ISereinIOC接口实现类 /// 当你将流程运行环境集成在你的项目时,并希望流程运行时使用你提供的对象,而非自动创建 @@ -15,7 +23,8 @@ namespace Serein.Library.Api /// 注意,是流程运行时,而非运行环境 /// /// - void UseExternalIOC(ISereinIOC ioc); + /// 用于每次启动时,重置IOC后默认注册某些类型 + void UseExternalIOC(ISereinIOC ioc, Action setDefultMemberOnReset = null); /// /// 开始运行流程 diff --git a/Library/Api/IFlowEnvironment.cs b/Library/Api/IFlowEnvironment.cs index 222e7c4..2288cdc 100644 --- a/Library/Api/IFlowEnvironment.cs +++ b/Library/Api/IFlowEnvironment.cs @@ -759,8 +759,7 @@ namespace Serein.Library.Api /// - /// 单例模式IOC容器,内部维护了一个实例字典,默认使用类型的FullName作为Key,如果以“接口-实现类”的方式注册,那么将使用接口类型的FullName作为Key。 - /// 当某个类型注册绑定成功后,将不会因为其它地方尝试注册相同类型的行为导致类型被重新创建。 + /// 运行环境使用的IOC,默认情况下无需对其进行调用 /// ISereinIOC IOC { get; } diff --git a/Library/FlowNode/DynamicContext.cs b/Library/FlowNode/DynamicContext.cs index c32262c..ca50cfc 100644 --- a/Library/FlowNode/DynamicContext.cs +++ b/Library/FlowNode/DynamicContext.cs @@ -15,7 +15,8 @@ namespace Serein.Library /// /// 动态流程上下文 /// - /// + /// 脚本运行时的IOC + /// 脚本运行时使用的IOC容器 public DynamicContext(IFlowEnvironment flowEnvironment) { Env = flowEnvironment; diff --git a/Library/FlowNode/LightweightFlowEnvironment.cs b/Library/FlowNode/LightweightFlowEnvironment.cs index 40644f7..a08d692 100644 --- a/Library/FlowNode/LightweightFlowEnvironment.cs +++ b/Library/FlowNode/LightweightFlowEnvironment.cs @@ -372,6 +372,8 @@ namespace Serein.Library private readonly IFlowEnvironment flowEnvironment; public static Serein.Library.Utils.ObjectPool FlowContextPool { get; set; } + public ISereinIOC IOC => throw new NotImplementedException(); + public LightweightFlowControl(IFlowCallTree flowCallTree, IFlowEnvironment flowEnvironment) { this.flowCallTree = flowCallTree; @@ -478,7 +480,12 @@ namespace Serein.Library public void UseExternalIOC(ISereinIOC ioc) { throw new NotImplementedException(); - } + } + + public void UseExternalIOC(ISereinIOC ioc, Action setDefultMemberOnReset = null) + { + throw new NotImplementedException(); + } #endregion } diff --git a/Library/FlowNode/NodeDebugSetting.cs b/Library/FlowNode/NodeDebugSetting.cs index cf979e0..72eaa1b 100644 --- a/Library/FlowNode/NodeDebugSetting.cs +++ b/Library/FlowNode/NodeDebugSetting.cs @@ -3,6 +3,7 @@ using Serein.Library.Api; using Serein.Library.Utils; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Text; using System.Threading.Tasks; @@ -77,7 +78,8 @@ namespace Serein.Library partial void OnIsInterruptChanged(bool oldValue, bool newValue) { - if (newValue && _getInterruptTask is null) + Debug.WriteLine($" {nameof(NodeDebugSetting)}.{nameof(NodeDebugSetting.OnIsInterruptChanged)} 暂未实现,需要重新设计中断逻辑"); + /*if (newValue && _getInterruptTask is null) { // 设置获取中断的委托 _getInterruptTask = () => NodeModel.Env.IOC.Get().WaitTriggerAsync(NodeModel.Guid); @@ -97,7 +99,7 @@ namespace Serein.Library _getInterruptTask = null; } - } + }*/ } diff --git a/Library/FlowNode/ParameterDetails.cs b/Library/FlowNode/ParameterDetails.cs index 267817b..61af606 100644 --- a/Library/FlowNode/ParameterDetails.cs +++ b/Library/FlowNode/ParameterDetails.cs @@ -335,7 +335,7 @@ namespace Serein.Library - #region “枚举-类型”转换器 + /*#region “枚举-类型”转换器 if (ExplicitType is not null && ExplicitType.IsEnum && DataType != ExplicitType) { var resultEnum = Enum.Parse(ExplicitType, DataValue); @@ -347,7 +347,7 @@ namespace Serein.Library return value; } } - #endregion + #endregion*/ // 需要获取预入参数据 object inputParameter; diff --git a/Library/Utils/BenchmarkHelpers.cs b/Library/Utils/BenchmarkHelpers.cs index 46b207d..4c61d1d 100644 --- a/Library/Utils/BenchmarkHelpers.cs +++ b/Library/Utils/BenchmarkHelpers.cs @@ -128,6 +128,7 @@ namespace Serein.Library.Utils total += ms; Console.WriteLine($"运行1次耗时 :{total} 毫秒:"); + Debug.WriteLine($"运行1次耗时 :{total} 毫秒:"); return result; } } diff --git a/Library/Utils/EmitHelper.cs b/Library/Utils/EmitHelper.cs index 8980b90..955a3f8 100644 --- a/Library/Utils/EmitHelper.cs +++ b/Library/Utils/EmitHelper.cs @@ -17,15 +17,26 @@ namespace Serein.Library.Utils public class EmitMethodInfo { + /// + /// 方法声明类型 + /// public Type DeclaringType { get; set; } + + /// + /// 方法类型 + /// + public EmitMethodType EmitMethodType { get; set; } + /// /// 是异步方法 /// - public bool IsTask { get; set; } + public bool IsAsync { get; set; } /// /// 是静态的 /// public bool IsStatic { get; set; } + + } public enum EmitMethodType @@ -41,16 +52,7 @@ namespace Serein.Library.Utils /// /// 有返回值的异步方法 /// - HasResultTask, - - /// - /// 普通的方法。如果方法返回void时,将会返回null。 - /// - StaticFunc, - /// - /// 无返回值的异步方法 - /// - StaticTask, + TaskHasResult, } public static bool IsGenericTask(Type returnType, out Type taskResult) @@ -179,26 +181,31 @@ namespace Serein.Library.Utils } // 处理返回值,如果没有返回值,则返回null il.Emit(OpCodes.Ret); // 返回 + EmitMethodType emitMethodType; if (IsTask) { if (IsTaskGenerics) { + emitMethodType = EmitMethodType.TaskHasResult; @delegate = dynamicMethod.CreateDelegate(typeof(Func>)); } else { + emitMethodType = EmitMethodType.Task; @delegate = dynamicMethod.CreateDelegate(typeof(Func)); } } else { + emitMethodType = EmitMethodType.Func; @delegate = dynamicMethod.CreateDelegate(typeof(Func)); } return new EmitMethodInfo { + EmitMethodType = emitMethodType, DeclaringType = methodInfo.DeclaringType, - IsTask = IsTask, + IsAsync = IsTask, IsStatic = isStatic }; } diff --git a/Library/Utils/LinqAsyncHelper.cs b/Library/Utils/LinqAsyncHelper.cs new file mode 100644 index 0000000..69e0cae --- /dev/null +++ b/Library/Utils/LinqAsyncHelper.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Serein.Library.Utils +{ + /// + /// 对于 linq 的异步扩展方法 + /// + public static class LinqAsyncHelper + { + public static async Task> SelectAsync(this IEnumerable source, + Func> method) + { + return await Task.WhenAll(source.Select(async s => await method(s))); + } + + public static async Task> SelectAsync(this IEnumerable source, + Func> method, + int concurrency = int.MaxValue) + { + var semaphore = new SemaphoreSlim(concurrency); + try + { + return await Task.WhenAll(source.Select(async s => + { + try + { + await semaphore.WaitAsync(); + return await method(s); + } + finally + { + semaphore.Release(); + } + })); + } + finally + { + semaphore.Dispose(); + } + } + } +} diff --git a/Library/Utils/SereinIoc.cs b/Library/Utils/SereinIoc.cs index 16c29de..e81482a 100644 --- a/Library/Utils/SereinIoc.cs +++ b/Library/Utils/SereinIoc.cs @@ -12,7 +12,7 @@ namespace Serein.Library.Utils { /// - /// 一个轻量级的IOC容器 + /// 一个轻量级的单例IOC容器 /// public class SereinIOC : ISereinIOC { @@ -45,7 +45,7 @@ namespace Serein.Library.Utils public event IOCMembersChangedHandler OnIOCMembersChanged; /// - /// 一个轻量级的IOC容器 + /// 一个轻量级的D单例IOC容器 /// public SereinIOC() { diff --git a/Net462DllTest/LogicControl/ViewLogicControl.cs b/Net462DllTest/LogicControl/ViewLogicControl.cs deleted file mode 100644 index 2d04f0d..0000000 --- a/Net462DllTest/LogicControl/ViewLogicControl.cs +++ /dev/null @@ -1,70 +0,0 @@ - -using Net462DllTest.Signal; -using Net462DllTest.Trigger; -using Serein.Library; -using Serein.Library.Api; -using Serein.Library.Utils; -using System; -using System.Threading.Tasks; -using System.Windows.Forms; - -namespace Net462DllTest.LogicControl -{ - - - - - [AutoRegister] - [DynamicFlow("[View]")] - public class ViewLogicControl - { - private readonly ViewManagement ViewManagement; - public ViewLogicControl(ViewManagement ViewManagement) - { - this.ViewManagement = ViewManagement; - } - - - #region 触发器节点 - - [NodeAction(NodeType.Flipflop, "等待视图命令")] - public async Task> WaitTask(CommandSignal command) - { - var result = await ViewManagement.WaitTriggerWithTimeoutAsync(command, TimeSpan.FromHours(10)); - if (result.Type == TriggerDescription.Overtime) - { - return new FlipflopContext(FlipflopStateType.Cancel, result.Value); - } - else - { - return new FlipflopContext(FlipflopStateType.Succeed, result.Value); - } - - } - - #endregion - - - [NodeAction(NodeType.Action, "打开窗体(转换器)")] - public void OpenForm2([EnumTypeConvertor(typeof(FromValue))] Form form, bool isTop = true) - { - // 枚举转换为对应的Type并自动实例化 - ViewManagement.OpenView(form, isTop); - } - - - - [NodeAction(NodeType.Action, "关闭指定类型的所有窗体")] - public void CloseForm(IDynamicContext context, FromValue fromId = FromValue.FromWorkBenchView) - { - var fromType = EnumHelper.GetBoundValue(fromId, attr => attr.Value); - if (fromType is null) return; - ViewManagement.CloseView(fromType); - } - - - - - - } -} diff --git a/Net462DllTest/Net462DllTest.csproj b/Net462DllTest/Net462DllTest.csproj index 886de87..727ee92 100644 --- a/Net462DllTest/Net462DllTest.csproj +++ b/Net462DllTest/Net462DllTest.csproj @@ -72,26 +72,12 @@ - - - - Form - - - FromWorkBenchView.cs - - - Form - - - TestFormView.cs - @@ -101,14 +87,6 @@ Serein.Library - - - FromWorkBenchView.cs - - - TestFormView.cs - - diff --git a/Net462DllTest/View/FromWorkBenchView.Designer.cs b/Net462DllTest/View/FromWorkBenchView.Designer.cs deleted file mode 100644 index f391229..0000000 --- a/Net462DllTest/View/FromWorkBenchView.Designer.cs +++ /dev/null @@ -1,110 +0,0 @@ -namespace Net462DllTest -{ - partial class FromWorkBenchView - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.button1 = new System.Windows.Forms.Button(); - this.textBoxPlcInfo = new System.Windows.Forms.TextBox(); - this.button2 = new System.Windows.Forms.Button(); - this.listBoxCommand = new System.Windows.Forms.ListBox(); - this.textBoxSpaceNum = new System.Windows.Forms.TextBox(); - this.SuspendLayout(); - // - // button1 - // - this.button1.Location = new System.Drawing.Point(220, 56); - this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(65, 23); - this.button1.TabIndex = 0; - this.button1.Text = "查看状态"; - this.button1.UseVisualStyleBackColor = true; - this.button1.Click += new System.EventHandler(this.button1_Click); - // - // textBoxPlcInfo - // - this.textBoxPlcInfo.Location = new System.Drawing.Point(35, 24); - this.textBoxPlcInfo.Name = "textBoxPlcInfo"; - this.textBoxPlcInfo.ReadOnly = true; - this.textBoxPlcInfo.Size = new System.Drawing.Size(250, 21); - this.textBoxPlcInfo.TabIndex = 1; - // - // button2 - // - this.button2.Location = new System.Drawing.Point(205, 181); - this.button2.Name = "button2"; - this.button2.Size = new System.Drawing.Size(80, 23); - this.button2.TabIndex = 2; - this.button2.Text = "触发"; - this.button2.UseVisualStyleBackColor = true; - this.button2.Click += new System.EventHandler(this.button2_Click); - // - // listBoxCommand - // - this.listBoxCommand.FormattingEnabled = true; - this.listBoxCommand.ItemHeight = 12; - this.listBoxCommand.Location = new System.Drawing.Point(35, 85); - this.listBoxCommand.Name = "listBoxCommand"; - this.listBoxCommand.Size = new System.Drawing.Size(250, 88); - this.listBoxCommand.TabIndex = 6; - // - // textBoxSpaceNum - // - this.textBoxSpaceNum.Location = new System.Drawing.Point(35, 183); - this.textBoxSpaceNum.Name = "textBoxSpaceNum"; - this.textBoxSpaceNum.Size = new System.Drawing.Size(106, 21); - this.textBoxSpaceNum.TabIndex = 7; - this.textBoxSpaceNum.Text = "104"; - // - // FromWorkBenchView - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(341, 251); - this.Controls.Add(this.textBoxSpaceNum); - this.Controls.Add(this.listBoxCommand); - this.Controls.Add(this.button2); - this.Controls.Add(this.textBoxPlcInfo); - this.Controls.Add(this.button1); - this.Name = "FromWorkBenchView"; - this.Text = "Form1"; - this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FromWorkBenchView_FormClosing); - this.Load += new System.EventHandler(this.FromWorkBenchView_Load); - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private System.Windows.Forms.Button button1; - private System.Windows.Forms.TextBox textBoxPlcInfo; - private System.Windows.Forms.Button button2; - private System.Windows.Forms.ListBox listBoxCommand; - private System.Windows.Forms.TextBox textBoxSpaceNum; - } -} \ No newline at end of file diff --git a/Net462DllTest/View/FromWorkBenchView.cs b/Net462DllTest/View/FromWorkBenchView.cs deleted file mode 100644 index d5d9c1e..0000000 --- a/Net462DllTest/View/FromWorkBenchView.cs +++ /dev/null @@ -1,59 +0,0 @@ - -using Net462DllTest.Signal; -using Net462DllTest.ViewModel; -using Serein.Library; -using Serein.Library.Api; -using Serein.Library.Utils; -using System; -using System.Windows.Forms; - -namespace Net462DllTest -{ - public partial class FromWorkBenchView : Form - { - private FromWorkBenchViewModel ViewModel; - - - public FromWorkBenchView(IFlowEnvironment env) - { - InitializeComponent(); - ViewModel = env.IOC.Get(); - if (ViewModel is null) - { - SereinEnv.WriteLine(InfoType.INFO, "创建对象并注入依赖项"); - ViewModel = env.IOC.CreateObject(); - } - BindData(); - } - - private void BindData() - { - textBoxPlcInfo.DataBindings.Add(nameof(textBoxPlcInfo.Text), ViewModel, nameof(ViewModel.DeviceInfo), false, DataSourceUpdateMode.OnPropertyChanged); - textBoxSpaceNum.DataBindings.Add(nameof(textBoxSpaceNum.Text), ViewModel, nameof(ViewModel.SpcaeNumber), false, DataSourceUpdateMode.OnPropertyChanged); - - listBoxCommand.DataSource = Enum.GetValues(typeof(CommandSignal)); - listBoxCommand.DataBindings.Add(nameof(listBoxCommand.SelectedItem), ViewModel, nameof(ViewModel.SelectedSignal), false, DataSourceUpdateMode.OnPropertyChanged); - listBoxCommand.SelectedIndexChanged += (s, e) => listBoxCommand.DataBindings[nameof(listBoxCommand.SelectedItem)].WriteValue(); - - } - private void FromWorkBenchView_Load(object sender, EventArgs e) - { - - } - - private void FromWorkBenchView_FormClosing(object sender, FormClosingEventArgs e) - { - ViewModel.CommandCloseForm.Execute(); - } - - private void button2_Click(object sender, EventArgs e) - { - ViewModel.CommandGetParkingSpace.Execute(); - } - - private void button1_Click(object sender, EventArgs e) - { - ViewModel.CommandViewPlcInfo.Execute(); - } - } -} diff --git a/Net462DllTest/View/FromWorkBenchView.resx b/Net462DllTest/View/FromWorkBenchView.resx deleted file mode 100644 index 1af7de1..0000000 --- a/Net462DllTest/View/FromWorkBenchView.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/Net462DllTest/View/TestFormView.Designer.cs b/Net462DllTest/View/TestFormView.Designer.cs deleted file mode 100644 index a27664b..0000000 --- a/Net462DllTest/View/TestFormView.Designer.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; - -namespace Net462DllTest.View -{ - partial class TestFormView - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.button1 = new System.Windows.Forms.Button(); - this.SuspendLayout(); - // - // button1 - // - this.button1.Location = new System.Drawing.Point(167, 58); - this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(75, 23); - this.button1.TabIndex = 0; - this.button1.Text = "测试"; - this.button1.UseVisualStyleBackColor = true; - this.button1.Click += new System.EventHandler(this.button1_Click); - // - // TestFormView - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(254, 118); - this.Controls.Add(this.button1); - this.Name = "TestFormView"; - this.Text = "TeseForm"; - this.ResumeLayout(false); - - } - - #endregion - - private System.Windows.Forms.Button button1; - } -} \ No newline at end of file diff --git a/Net462DllTest/View/TestFormView.cs b/Net462DllTest/View/TestFormView.cs deleted file mode 100644 index 9fb49f3..0000000 --- a/Net462DllTest/View/TestFormView.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Windows.Forms; - -namespace Net462DllTest.View -{ - public partial class TestFormView : Form - { - - public TestFormView() - { - InitializeComponent(); - - } - - private void button1_Click(object sender, EventArgs e) - { - } - } -} diff --git a/Net462DllTest/View/TestFormView.resx b/Net462DllTest/View/TestFormView.resx deleted file mode 100644 index 1af7de1..0000000 --- a/Net462DllTest/View/TestFormView.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/Net462DllTest/ViewModel/FromWorkBenchViewModel.cs b/Net462DllTest/ViewModel/FromWorkBenchViewModel.cs deleted file mode 100644 index 5c86dd5..0000000 --- a/Net462DllTest/ViewModel/FromWorkBenchViewModel.cs +++ /dev/null @@ -1,140 +0,0 @@ -using Net462DllTest.Model; -using Net462DllTest.Signal; -using Net462DllTest.Trigger; -using Net462DllTest.Utils; -using Serein.Library.Network.WebSocketCommunication; -using System.ComponentModel; - -namespace Net462DllTest.ViewModel -{ - public class LibSpace - { - public string SpaceNum { get; set; } - public string PlateNumber { get; set; } - - public override string ToString() - { - return $"{nameof(SpaceNum)}{SpaceNum}{nameof(PlateNumber)}{PlateNumber}"; - } - } - - public class FromWorkBenchViewModel : INotifyPropertyChanged - { - - private readonly SiemensPlcDevice Device; - private readonly ViewManagement viewManagement; - private readonly PlcVarModelDataProxy plcVarModelDataProxy; - - - - public FromWorkBenchViewModel(SiemensPlcDevice Device, - ViewManagement viewManagement, - PlcVarModelDataProxy plcVarModelDataProxy, - WebSocketServer webSocketServer) - { - this.Device = Device; - this.viewManagement = viewManagement; - this.plcVarModelDataProxy = plcVarModelDataProxy; - - InitCommand(); // 初始化指令 - } - - - - - - #region 属性绑定 - private string _spcaeNumber; - public string SpcaeNumber - { - get { return _spcaeNumber; } - set - { - if (_spcaeNumber != value) - { - _spcaeNumber = value; - OnPropertyChanged(nameof(SpcaeNumber)); - } - } - } - - private CommandSignal _selectedSignal; - public CommandSignal SelectedSignal - { - get { return _selectedSignal; } - set - { - if (_selectedSignal != value) - { - _selectedSignal = value; - OnPropertyChanged(nameof(SelectedSignal)); - } - } - } - - private string _deviceInfo; - public string DeviceInfo - { - get { return _deviceInfo; } - set - { - if (_deviceInfo != value) - { - _deviceInfo = value; - OnPropertyChanged(nameof(DeviceInfo)); - } - } - } - - public event PropertyChangedEventHandler PropertyChanged; - - protected void OnPropertyChanged(string propertyName) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - - - #endregion - - #region 操作绑定 - - /// - /// 查看PLC信息 - /// - public RelayCommand CommandViewPlcInfo { get; private set; } - /// - /// 调取车位 - /// - public RelayCommand CommandGetParkingSpace { get; private set; } - /// - /// 关闭窗体 - /// - public RelayCommand CommandCloseForm { get; private set; } - - public void InitCommand() - { - CommandViewPlcInfo = new RelayCommand((p) => - { - DeviceInfo = Device?.ToString(); - }); - CommandGetParkingSpace = new RelayCommand((p) => - { - _ = viewManagement.InvokeTriggerAsync(SelectedSignal, SpcaeNumber); - }); - CommandCloseForm = new RelayCommand((p) => - { - - }); - - - } - - #endregion - - - } - - - - -} diff --git a/Net462DllTest/Web/PlcSocketService.cs b/Net462DllTest/Web/PlcSocketService.cs index bf00bc9..5355e8a 100644 --- a/Net462DllTest/Web/PlcSocketService.cs +++ b/Net462DllTest/Web/PlcSocketService.cs @@ -33,23 +33,25 @@ namespace Net462DllTest.Web [NodeAction(NodeType.Init)] public void Init(IDynamicContext context) { - context.Env.IOC.Register(); - context.Env.IOC.Register(); + var ioc = context.Env.FlowControl.IOC; + ioc.Register(); + ioc.Register(); - context.Env.IOC.Register(); - context.Env.IOC.Register(); + ioc.Register(); + ioc.Register(); } [NodeAction(NodeType.Loading)] // Loading 初始化完成已注入依赖项,可以开始逻辑上的操作 public void Loading(IDynamicContext context) { + var ioc = context.Env.FlowControl.IOC; // 注册控制器 - context.Env.IOC.Run((router, apiServer) => { + ioc.Run((router, apiServer) => { router.AddHandle(typeof(FlowController)); apiServer.Start("http://*:8089/"); // 开启 Web Api 服务 }); - context.Env.IOC.Run(async (socketServer) => { + ioc.Run(async (socketServer) => { socketServer.MsgHandleHelper.AddModule(this, (ex, recover) => { recover(new @@ -61,7 +63,7 @@ namespace Net462DllTest.Web }); await socketServer.StartAsync("http://localhost:5005/"); // 开启 Web Socket 监听 }); - context.Env.IOC.Run(async client => { + ioc.Run(async client => { await client.ConnectAsync("ws://localhost:5005/"); // 连接到服务器 }); } @@ -69,12 +71,13 @@ namespace Net462DllTest.Web [NodeAction(NodeType.Exit)] // 流程结束时自动执行 public void Exit(IDynamicContext context) { - context.Env.IOC.Run((apiServer) => + var ioc = context.Env.FlowControl.IOC; + ioc.Run((apiServer) => { apiServer?.Stop(); // 关闭 Web 服务 }); - context.Env.IOC.Run((socketServer) => + ioc.Run((socketServer) => { socketServer.MsgHandleHelper.RemoveModule(this); socketServer?.Stop(); // 关闭 Web 服务 diff --git a/NodeFlow/Env/FlowControl.cs b/NodeFlow/Env/FlowControl.cs index cebe6a5..d9ea392 100644 --- a/NodeFlow/Env/FlowControl.cs +++ b/NodeFlow/Env/FlowControl.cs @@ -35,19 +35,44 @@ namespace Serein.NodeFlow.Env this.flowOperationService = flowOperationService; this.flowModelService = flowModelService; this.UIContextOperation = UIContextOperation; + contexts = new ObjectPool(() => new DynamicContext(flowEnvironment)); } private ObjectPool contexts; private FlowWorkManagement flowWorkManagement; - private ISereinIOC sereinIOC; - - + private ISereinIOC externalIOC; + private Action setDefultMemberOnReset; + private bool IsUseExternalIOC = false; + private object lockObj = new object(); /// /// 如果全局触发器还在运行,则为 Running 。 /// private RunState FlipFlopState = RunState.NoStart; + /// + /// 运行时的IOC容器 + /// + public ISereinIOC IOC + { + get + { + lock (lockObj) + { + if (externalIOC is null) externalIOC = new SereinIOC(); + return externalIOC; + } + + } + private set + { + lock (lockObj) + { + externalIOC = value; + } + } + } + /// public async Task StartFlowAsync(string[] canvasGuids) { @@ -104,13 +129,14 @@ namespace Serein.NodeFlow.Env flowTasks.Add(guid, ft); } #endregion - - sereinIOC.Reset(); - sereinIOC.Register(() => flowEnvironment); - sereinIOC.Register(); // 注册脚本接口 + IOC.Reset(); + setDefultMemberOnReset?.Invoke(IOC); + IOC.Register(() => flowEnvironment); + //externalIOC.Register(); // 注册脚本接口 var flowTaskOptions = new FlowWorkOptions { + FlowIOC = IOC, Environment = flowEnvironment, // 流程 Flows = flowTasks, FlowContextPool = contexts, // 上下文对象池 @@ -143,9 +169,9 @@ namespace Serein.NodeFlow.Env /// public async Task StartFlowAsync(string startNodeGuid) { - var flowTaskOptions = new FlowWorkOptions { + FlowIOC = IOC, Environment = flowEnvironment, // 流程 FlowContextPool = contexts, // 上下文对象池 }; @@ -203,7 +229,7 @@ namespace Serein.NodeFlow.Env { flowWorkManagement?.Exit(); UIContextOperation?.Invoke(() => flowEnvironmentEvent.OnFlowRunComplete(new FlowEventArgs())); - sereinIOC.Reset(); + IOC.Reset(); flowWorkManagement = null; GC.Collect(); return Task.FromResult(true); @@ -240,9 +266,11 @@ namespace Serein.NodeFlow.Env }*/ } /// - public void UseExternalIOC(ISereinIOC ioc) + public void UseExternalIOC(ISereinIOC ioc, Action setDefultMemberOnReset = null) { - this.sereinIOC = ioc; // 设置IOC容器 + IOC = ioc; // 设置IOC容器 + this.setDefultMemberOnReset = setDefultMemberOnReset; + IsUseExternalIOC = true; } /// public void MonitorObjectNotification(string nodeGuid, object monitorData, MonitorObjectEventArgs.ObjSourceType sourceType) @@ -270,10 +298,6 @@ namespace Serein.NodeFlow.Env /// public async Task InvokeAsync(string apiGuid, Dictionary dict) { - if (sereinIOC is null) - { - sereinIOC = flowEnvironment.IOC; - } if (!flowModelService.TryGetNodeModel(apiGuid, out var nodeModel)) { throw new ArgumentNullException($"不存在流程接口:{apiGuid}"); diff --git a/NodeFlow/Env/FlowEdit.cs b/NodeFlow/Env/FlowEdit.cs index 6b32046..8307009 100644 --- a/NodeFlow/Env/FlowEdit.cs +++ b/NodeFlow/Env/FlowEdit.cs @@ -161,7 +161,7 @@ namespace Serein.NodeFlow.Env } #endregion - nodeModel = FlowNodeExtension.CreateNode(flowEnvironment, controlType, methodDetails); // 加载项目时创建节点 + nodeModel = FlowNodeExtension.CreateNode(flowEnvironment.IOC, controlType, methodDetails); // 加载项目时创建节点 if (nodeModel is null) { nodeInfo.Guid = string.Empty; diff --git a/NodeFlow/FlowNodeExtension.cs b/NodeFlow/FlowNodeExtension.cs index ea2c446..9cccdf7 100644 --- a/NodeFlow/FlowNodeExtension.cs +++ b/NodeFlow/FlowNodeExtension.cs @@ -1,6 +1,7 @@ using Serein.Library; using Serein.Library.Api; using Serein.Library.Utils; +using Serein.NodeFlow.Env; using Serein.NodeFlow.Model; using System.Collections.Concurrent; using System.ComponentModel; @@ -51,18 +52,17 @@ namespace Serein.NodeFlow /// /// 创建节点 /// - /// 运行环境 + /// 运行环境使用的IOC /// 节点类型 /// 方法描述 /// /// - public static IFlowNode CreateNode(IFlowEnvironment env, NodeControlType nodeControlType, - MethodDetails? methodDetails = null) + public static IFlowNode CreateNode(ISereinIOC envIOC, NodeControlType nodeControlType, MethodDetails? methodDetails = null) { // 尝试获取需要创建的节点类型 - - if (!env.FlowEdit.NodeMVVMManagement.TryGetType(nodeControlType, out var nodeMVVM) || nodeMVVM.ModelType == null) + var flowEdit = envIOC.Get(); + if (!flowEdit.NodeMVVMManagement.TryGetType(nodeControlType, out var nodeMVVM) || nodeMVVM.ModelType == null) { throw new Exception($"无法创建{nodeControlType}节点,节点类型尚未注册。"); } @@ -70,7 +70,7 @@ namespace Serein.NodeFlow // 生成实例 //var nodeObj = Activator.CreateInstance(nodeMVVM.ModelType, env); - var nodeObj = env.IOC.CreateObject(nodeMVVM.ModelType); + var nodeObj = envIOC.CreateObject(nodeMVVM.ModelType); if (nodeObj is not IFlowNode nodeModel) { throw new Exception($"无法创建目标节点类型的实例[{nodeControlType}]"); diff --git a/NodeFlow/FlowWorkOptions.cs b/NodeFlow/FlowWorkOptions.cs index caf4463..b512196 100644 --- a/NodeFlow/FlowWorkOptions.cs +++ b/NodeFlow/FlowWorkOptions.cs @@ -33,6 +33,10 @@ namespace Serein.NodeFlow /// public class FlowWorkOptions() { + /// + /// 流程IOC容器 + /// + public ISereinIOC FlowIOC { get; set; } /// /// 流程运行环境 /// @@ -46,7 +50,7 @@ namespace Serein.NodeFlow /// /// 上下文线程池 /// - public Serein.Library.Utils.ObjectPool FlowContextPool { get; set; } + public Serein.Library.Utils.ObjectPool FlowContextPool { get; set; } /// /// 每个画布需要启用的节点 diff --git a/NodeFlow/Model/Node/NodeModelBaseFunc.cs b/NodeFlow/Model/Node/NodeModelBaseFunc.cs index 7916b40..4967871 100644 --- a/NodeFlow/Model/Node/NodeModelBaseFunc.cs +++ b/NodeFlow/Model/Node/NodeModelBaseFunc.cs @@ -141,11 +141,11 @@ namespace Serein.NodeFlow.Model } else { - var instance = Env.IOC.Get(md.ActingInstanceType); + var instance = Env.FlowControl.IOC.Get(md.ActingInstanceType); if (instance is null) { - Env.IOC.Register(md.ActingInstanceType).Build(); - instance = Env.IOC.Get(md.ActingInstanceType); + Env.FlowControl.IOC.Register(md.ActingInstanceType).Build(); + instance = Env.FlowControl.IOC.Get(md.ActingInstanceType); } object[] args = await this.GetParametersAsync(context, token); var result = await dd.InvokeAsync(instance, args); diff --git a/NodeFlow/Model/Node/SingleFlipflopNode.cs b/NodeFlow/Model/Node/SingleFlipflopNode.cs index 1ff3aad..08b50a4 100644 --- a/NodeFlow/Model/Node/SingleFlipflopNode.cs +++ b/NodeFlow/Model/Node/SingleFlipflopNode.cs @@ -39,11 +39,11 @@ namespace Serein.NodeFlow.Model throw new Exception("不存在对应委托"); } - var instance = context.Env.IOC.Get(md.ActingInstanceType); + var instance = Env.FlowControl.IOC.Get(md.ActingInstanceType); if (instance is null) { - Env.IOC.Register(md.ActingInstanceType).Build(); - instance = Env.IOC.Get(md.ActingInstanceType); + Env.FlowControl.IOC.Register(md.ActingInstanceType).Build(); + instance = Env.FlowControl.IOC.Get(md.ActingInstanceType); } await dd.InvokeAsync(instance, [context]); var args = await this.GetParametersAsync(context, token); diff --git a/NodeFlow/Model/Node/SingleFlowCallNode.cs b/NodeFlow/Model/Node/SingleFlowCallNode.cs index 18ef262..433e117 100644 --- a/NodeFlow/Model/Node/SingleFlowCallNode.cs +++ b/NodeFlow/Model/Node/SingleFlowCallNode.cs @@ -246,6 +246,10 @@ namespace Serein.NodeFlow.Model } else { + /*var tempName = node.MethodDetails.MethodName; + var index = node.MethodDetails.MethodName.IndexOf('('); + var methodName = tempName[..(index - 1)]; + return GetApiInvokeName(node, methodName);*/ FlowLibraryService service = node.Env.IOC.Get(); if (service.TryGetMethodInfo(md.AssemblyName, md.MethodName, out var methodInfo)) { diff --git a/NodeFlow/Model/Operation/CreateNodeOperation.cs b/NodeFlow/Model/Operation/CreateNodeOperation.cs index bf61998..d0caf9a 100644 --- a/NodeFlow/Model/Operation/CreateNodeOperation.cs +++ b/NodeFlow/Model/Operation/CreateNodeOperation.cs @@ -69,11 +69,11 @@ namespace Serein.NodeFlow.Model.Operation public override async Task ExecuteAsync() { if (!ValidationParameter()) return false; // 执行时验证 - + IFlowNode? nodeModel; if (IsBaseNode) { - nodeModel = FlowNodeExtension.CreateNode(flowEnvironment, NodeControlType); // 加载基础节点 + nodeModel = FlowNodeExtension.CreateNode(flowEnvironment.IOC, NodeControlType); // 加载基础节点 } else { @@ -89,7 +89,7 @@ namespace Serein.NodeFlow.Model.Operation return false; //throw new InvalidOperationException($"无法创建节点,因为没有找到{MethodDetailsInfo.AssemblyName}.{MethodDetailsInfo.MethodName}方法,请检查是否已加载对应程序集"); } - nodeModel = FlowNodeExtension.CreateNode(flowEnvironment, NodeControlType, methodDetails); // 一般的加载节点方法 + nodeModel = FlowNodeExtension.CreateNode(flowEnvironment.IOC, NodeControlType, methodDetails); // 一般的加载节点方法 } nodeModel.Guid ??= Guid.NewGuid().ToString(); diff --git a/NodeFlow/Services/FlowWorkManagement.cs b/NodeFlow/Services/FlowWorkManagement.cs index 4395a9f..febdb0f 100644 --- a/NodeFlow/Services/FlowWorkManagement.cs +++ b/NodeFlow/Services/FlowWorkManagement.cs @@ -113,8 +113,9 @@ namespace Serein.NodeFlow.Services private bool RegisterAllType(List nodes) { var env = WorkOptions.Environment; + var ioc = WorkOptions.FlowIOC; + - var nodeMds = nodes.Select(item => item.MethodDetails).ToList(); // 获取环境中所有节点的方法信息 var allMds = new List(); @@ -127,7 +128,7 @@ namespace Serein.NodeFlow.Services { if (md.ActingInstanceType != null) { - env.IOC.Register(md.ActingInstanceType); + ioc.Register(md.ActingInstanceType); } else { @@ -135,10 +136,10 @@ namespace Serein.NodeFlow.Services isSuccessful = false ; } } - env.IOC.Build(); // 绑定初始化时注册的类型 + ioc.Build(); // 绑定初始化时注册的类型 foreach (var md in allMds) { - var instance = env.IOC.Get(md.ActingInstanceType); + var instance = ioc.Get(md.ActingInstanceType); if (instance is null) { SereinEnv.WriteLine(InfoType.ERROR, $"{md.MethodName} - 无法获取类型[{md.ActingInstanceType}]的实例"); @@ -154,7 +155,7 @@ namespace Serein.NodeFlow.Services var env = WorkOptions.Environment; var initMds = WorkOptions.InitMds; var pool = WorkOptions.FlowContextPool; - var ioc = WorkOptions.Environment.IOC; + var ioc = WorkOptions.FlowIOC; foreach (var md in initMds) // 初始化 { if (!env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) // 流程运行初始化 @@ -167,7 +168,7 @@ namespace Serein.NodeFlow.Services context.Reset(); pool.Free(context); } - env.IOC.Build(); // 绑定初始化时注册的类型 + ioc.Build(); // 绑定初始化时注册的类型 var isSuccessful = true; return isSuccessful; } @@ -176,7 +177,7 @@ namespace Serein.NodeFlow.Services var env = WorkOptions.Environment; var loadMds = WorkOptions.LoadMds; var pool = WorkOptions.FlowContextPool; - var ioc = WorkOptions.Environment.IOC; + var ioc = WorkOptions.FlowIOC; foreach (var md in loadMds) // 加载时 { if (!env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) // 流程运行初始化 @@ -189,7 +190,7 @@ namespace Serein.NodeFlow.Services context.Reset(); pool.Free(context); } - env.IOC.Build(); // 绑定初始化时注册的类型 + ioc.Build(); // 绑定初始化时注册的类型 var isSuccessful = true; return isSuccessful; @@ -199,7 +200,7 @@ namespace Serein.NodeFlow.Services var env = WorkOptions.Environment; var mds = WorkOptions.ExitMds; var pool = WorkOptions.FlowContextPool; - var ioc = WorkOptions.Environment.IOC; + var ioc = WorkOptions.FlowIOC; // var fit = ioc.Get(); // fit.CancelAllTrigger(); // 取消所有中断 diff --git a/Serein.Script/IScriptInvokeContext.cs b/Serein.Script/IScriptInvokeContext.cs index 48529bd..7c63a38 100644 --- a/Serein.Script/IScriptInvokeContext.cs +++ b/Serein.Script/IScriptInvokeContext.cs @@ -13,7 +13,7 @@ namespace Serein.Script IDynamicContext FlowContext { get; } /// - /// 是否该退出了(由外部发出停止信号) + /// 是否该退出了(由 TokenSource 控制,用于响应外部发出停止信号) /// bool IsReturn { get; } @@ -40,7 +40,7 @@ namespace Serein.Script /// /// /// - bool SetVarValue(string varName, object value); + bool SetVarValue(string varName, object? value); /// /// 结束调用 diff --git a/Serein.Script/Node/AssignmentNode.cs b/Serein.Script/Node/AssignmentNode.cs index 04d43e8..a8486b6 100644 --- a/Serein.Script/Node/AssignmentNode.cs +++ b/Serein.Script/Node/AssignmentNode.cs @@ -8,17 +8,16 @@ namespace Serein.Script.Node { /// - /// 赋值节点 + /// 变量赋值节点 /// public class AssignmentNode : ASTNode { /// /// 变量名称 /// - //public string Variable { get; } public ASTNode Target { get; } /// - /// 对应的节点 + /// 值来源 /// public ASTNode Value { get; } diff --git a/Serein.Script/ScriptInvokeContext.cs b/Serein.Script/ScriptInvokeContext.cs index b6c30c0..ce98d2d 100644 --- a/Serein.Script/ScriptInvokeContext.cs +++ b/Serein.Script/ScriptInvokeContext.cs @@ -14,7 +14,7 @@ namespace Serein.Script /// /// 定义的变量 /// - private Dictionary _variables = new Dictionary(); + private Dictionary _variables = new Dictionary(); /// /// 取消令牌源,用于控制脚本的执行 diff --git a/Serein.Script/SereinSciptException.cs b/Serein.Script/SereinSciptException.cs index 83295b8..47d2380 100644 --- a/Serein.Script/SereinSciptException.cs +++ b/Serein.Script/SereinSciptException.cs @@ -13,4 +13,5 @@ namespace Serein.Script Message = $"异常信息 : {message} ,代码在第{node.Row}行: {node.Code.Trim()}"; } } + } diff --git a/Serein.Script/SereinScript.cs b/Serein.Script/SereinScript.cs index 5bd5644..d5283c4 100644 --- a/Serein.Script/SereinScript.cs +++ b/Serein.Script/SereinScript.cs @@ -10,6 +10,9 @@ using System.Threading.Tasks; namespace Serein.Script { + + + public class SereinScript { /// @@ -47,7 +50,7 @@ namespace Serein.Script } Dictionary symbolInfos = TypeAnalysis.NodeSymbolInfos.ToDictionary(); SereinScriptInterpreter Interpreter = new SereinScriptInterpreter(symbolInfos); - return await Interpreter.InterpretAsync(context, programNode); + return await Interpreter.InterpreterAsync(context, programNode); } diff --git a/Serein.Script/SereinScriptInterpreter.cs b/Serein.Script/SereinScriptInterpreter.cs index 03ab98c..0bc87ed 100644 --- a/Serein.Script/SereinScriptInterpreter.cs +++ b/Serein.Script/SereinScriptInterpreter.cs @@ -3,445 +3,342 @@ using Serein.Library; using Serein.Library.Utils; using Serein.Script.Node; using Serein.Script.Node.FlowControl; +using System; using System.ComponentModel.Design; +using System.Reactive; using System.Reflection; using System.Reflection.Metadata.Ecma335; using System.Runtime.CompilerServices; using System.Threading.Tasks; using System.Xml.Linq; - namespace Serein.Script { /// - /// 脚本解释器,负责解析和执行 Serein 脚本 + /// 脚本解释器,负责执行 Serein 脚本 /// public class SereinScriptInterpreter { private readonly Dictionary symbolInfos; + /// + /// 缓存对象方法调用节点 + /// + private Dictionary MethodNodeDelegateCaches { get; } = new Dictionary(); public SereinScriptInterpreter(Dictionary symbolInfos) { this.symbolInfos = symbolInfos; } - - - - /// - /// 入口节点 - /// - /// - /// - private async Task ExecutionProgramNodeAsync(IScriptInvokeContext context,ProgramNode programNode) + public async Task InterpreterAsync(IScriptInvokeContext context, ProgramNode programNode) { - // 加载变量 - ASTNode statement = null; - try + var nodes = programNode.Statements; + object? result = null; + foreach (var node in nodes) { - // 遍历 ProgramNode 中的所有语句并执行它们 - for (int index = 0; index < programNode.Statements.Count; index++) - { - statement = programNode.Statements[index]; - // 直接退出 - if (statement is ReturnNode returnNode) // 遇到 Return 语句 提前退出 - { - return await EvaluateAsync(context, statement); - } - else - { - var result = await InterpretAsync(context, statement); - if (context.IsNeedReturn) - { - return result; - } - } - } - return null; - } - catch (Exception ex ) - { - if(statement is not null) - { - SereinEnv.WriteLine(InfoType.ERROR, $"脚本异常发生在[行{statement.Row}]:{ex.Message}{Environment.NewLine}\t{statement.Code}"); - } - throw; + result = await InterpretAsync(context, node); // 解释每个节点 + if (context.IsReturn) break; // 如果需要提前返回,则停止执行 } + return result; // 返回最后一个节点的结果 } - /// - /// 类型定义 - /// - /// - /// - private void ExecutionClassTypeDefinitionNode(ClassTypeDefinitionNode classTypeDefinitionNode) - { - var className = classTypeDefinitionNode.ClassType.TypeName; - if (SereinScript.MountType.ContainsKey(className) && !classTypeDefinitionNode.IsOverlay) - { - //SereinEnv.WriteLine(InfoType.WARN, $"异常信息 : 类型重复定义,代码在第{classTypeDefinitionNode.Row}行: {classTypeDefinitionNode.Code.Trim()}"); - return; - } - if(DynamicObjectHelper.GetCacheType(className) == null) - { - var propertyTypes = classTypeDefinitionNode.Propertys.ToDictionary(p => p.Key, p => symbolInfos[p.Value]); - var type = DynamicObjectHelper.CreateTypeWithProperties(propertyTypes, className); // 覆盖 - SereinScript.MountType[className] = type; // 定义对象 - } - - } - - /// - /// IF...ELSE... 语句块 - /// - /// - /// - /// - private async Task ExecutionIfNodeAsync(IScriptInvokeContext context, IfNode ifNode) - { - var result = await EvaluateAsync(context, ifNode.Condition) ?? throw new SereinSciptException(ifNode, $"条件语句返回了 null"); - - if (result is not bool condition) - { - throw new SereinSciptException(ifNode, "条件语句返回值不为 bool 类型"); - } - - var branchNodes = condition ? ifNode.TrueBranch : ifNode.FalseBranch; - if(branchNodes is null || branchNodes.Count < 1) - { - return null; - } - else - { - - foreach (var branchNode in branchNodes) + /* + async Task InterpreterAsync(IScriptInvokeContext context, ProgramNode node) { - if (branchNode is ReturnNode) // 遇到 Return 语句 提前退出 - { - var reulst = await EvaluateAsync(context, branchNode); - context.IsNeedReturn = true; - return reulst; - } - else - { - await InterpretAsync(context, branchNode); - } - } - return null; - } - - } - - /// - /// WHILE(){...} 语句块 - /// - /// - /// - /// - private async Task ExectutionWhileNodeAsync(IScriptInvokeContext context, WhileNode whileNode) - { - - while (true) - { - if (context.IsReturn) // 停止流程 - { - throw new SereinSciptException(whileNode, $"while循环已由外部主动停止"); - } - var result = await EvaluateAsync(context, whileNode.Condition) ?? throw new SereinSciptException(whileNode, $"条件语句返回了 null"); - if (result is not bool condition) - { - throw new SereinSciptException(whileNode, $"条件语句返回值不为 bool 类型(当前返回值类型为 {result.GetType()})"); - } - if (!condition) - { - break; - } - foreach(var branchNode in whileNode.Body) - { - if (branchNode is ReturnNode) // 遇到 Return 语句 提前退出 - { - var reulst = await EvaluateAsync(context, branchNode); - context.IsNeedReturn = true; - return reulst; - } - else - { - await InterpretAsync(context, branchNode); - } - //await InterpretAsync(context, node); - } - } - return null; - } - - /// - /// 操作节点 - /// - /// - /// - private async Task ExecutionAssignmentNodeAsync(IScriptInvokeContext context, AssignmentNode assignmentNode) - { - if(assignmentNode.Target is IdentifierNode identifierNode) - { - var value = await EvaluateAsync(context, assignmentNode.Value); - if (value is not null) - { - context.SetVarValue(identifierNode.Name, value); - } - } - else - { - - } - /*var targetObject = await EvaluateAsync(context, assignmentNode.TargetNode); - var value = await EvaluateAsync(context, assignmentNode.Value); - if(value is not null) - { - context.SetVarValue(targetObject, value); - }*/ - } - - - - private async Task InterpretFunctionCallAsync(IScriptInvokeContext context, FunctionCallNode functionCallNode) - { - if (functionCallNode.FunctionName.Equals("GetFlowContext", StringComparison.OrdinalIgnoreCase)) - { - return context.FlowContext; - } - - // 评估函数参数 - var arguments = new object?[functionCallNode.Arguments.Count]; - for (int i = 0; i < functionCallNode.Arguments.Count; i++) - { - ASTNode? arg = functionCallNode.Arguments[i]; - arguments[i] = await EvaluateAsync(context, arg); // 评估每个参数 - } - - var funcName = functionCallNode.FunctionName; - - object? instance = null; // 静态方法不需要传入实例,所以可以传入null - - - // 查找并执行对应的函数 - if (SereinScript.FunctionDelegates .TryGetValue(funcName, out DelegateDetails? function)) - { - if (!function.EmitMethodInfo.IsStatic) - { - if(SereinScript.DelegateInstances.TryGetValue(funcName, out var action)) - { - instance = action.Invoke();// 非静态的方法需要获取相应的实例 - - if (instance is null) - { - throw new SereinSciptException(functionCallNode, $"函数 {funcName} 尝试获取实例时返回了 null "); - } - } - else - { - throw new SereinSciptException(functionCallNode, $"挂载函数 {funcName} 时需要同时给定获取实例的 Func"); - } - } - - var result = await function.InvokeAsync(instance,arguments); - return result; - } - else - { - throw new Exception($"Unknown function: {functionCallNode.FunctionName}"); - } - } - - - /// - /// 解释操作 - /// - /// - /// - /// - /// - public async Task InterpretAsync(IScriptInvokeContext context, ASTNode node) - { - if(node == null) - { - return null; - } - - switch (node) - { - case ProgramNode programNode: // AST树入口 - - var scritResult = await ExecutionProgramNodeAsync(context, programNode); - return scritResult; // 遍历 ProgramNode 中的所有语句并执行它们 - case ClassTypeDefinitionNode classTypeDefinitionNode: // 定义类型 - ExecutionClassTypeDefinitionNode(classTypeDefinitionNode); - break; - case AssignmentNode assignment: // 出现在 = 右侧的表达式 - await ExecutionAssignmentNodeAsync(context, assignment); - break; - case CollectionAssignmentNode collectionAssignmentNode: - await SetCollectionValue(context,collectionAssignmentNode); - break; - case ExpressionNode objectMemberExpressionNode: - break; - case MemberAssignmentNode memberAssignmentNode: // 设置对象属性 - await SetMemberValue(context, memberAssignmentNode); - break; - case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用 - return await CallMemberFunction(context, memberFunctionCallNode); - case IfNode ifNode: // 执行 if...else... 语句块 - return await ExecutionIfNodeAsync(context, ifNode); - break; - case WhileNode whileNode: // 循环语句块 - return await ExectutionWhileNodeAsync(context, whileNode); - break; - case FunctionCallNode functionCallNode: // 方法调用节点 - return await InterpretFunctionCallAsync(context, functionCallNode); - case ReturnNode returnNode: - return await EvaluateAsync(context, returnNode); - default: - throw new SereinSciptException(node, "解释器 InterpretAsync() 未实现节点行为"); - } - return null; - } - - /// - /// 评估 - /// - /// - /// - /// - /// - private async Task EvaluateAsync(IScriptInvokeContext context, ASTNode node) - { - if(node == null) - { - return null; - } - switch (node) - { - case NullNode nullNode: return null; - case BooleanNode booleanNode: - return booleanNode.Value; // 返回数值 - case NumberIntNode numberNode: - return numberNode.Value; // 返回 int 整型数 - case NumberLongNode numberNode: - return numberNode.Value; // 返回 long 整型数 - case NumberFloatNode numberNode: - return numberNode.Value; // 返回 float 浮点型 - case NumberDoubleNode numberNode: - return numberNode.Value; // 返回 double 浮点型 - case StringNode stringNode: - return stringNode.Value; // 返回字符串值 - case CharNode charNode: - return charNode.Value; // 返回Char - case IdentifierNode identifierNode: - return context.GetVarValue(identifierNode.Name); - //throw new SereinSciptException(identifierNode, "尝试使用值为null的变量"); - //throw new SereinSciptException(identifierNode, "尝试使用未声明的变量"); - case BinaryOperationNode binOpNode: - // 递归计算二元操作 - var left = await EvaluateAsync(context, binOpNode.Left); - //if (left == null ) throw new SereinSciptException(binOpNode.Left, $"左值尝试使用 null"); - var right = await EvaluateAsync(context, binOpNode.Right); - //if (right == null) throw new SereinSciptException(binOpNode.Right, "右值尝试使用计算 null"); - return EvaluateBinaryOperation(left, binOpNode.Operator, right); - case ObjectInstantiationNode objectInstantiationNode: // 对象实例化 - if (!SereinScript.MountType.TryGetValue(objectInstantiationNode.Type.TypeName, out var type)) + } + return await InterpreterAsync(context, node); + */ + private async Task InterpretAsync(IScriptInvokeContext context, ASTNode node) + { + switch (node) + { + case ProgramNode programNode: // 程序开始节点 + throw new Exception(); + case ReturnNode returnNode: // 程序退出节点 + async Task InterpreterReturnNodeAsync(IScriptInvokeContext context, ReturnNode returnNode) { - type = symbolInfos[objectInstantiationNode.Type]; - if (type is null) + object? returnValue = await InterpretAsync(context, returnNode.Value); + context.IsNeedReturn = true; + return returnValue; + } + return await InterpreterReturnNodeAsync(context, returnNode); + #region 字面量节点 + case NullNode nullNode: // null + return null; // 返回 null + case CharNode charNode: // char字面量 + return charNode.Value; // 返回字符值 + case StringNode stringNode: // 字符串字面量 + return stringNode.Value; // 返回字符串值 + case BooleanNode booleanNode: // 布尔值字面量 + return booleanNode.Value; // 返回布尔值 + case NumberIntNode numberIntNode: // int整型数值字面量 + return numberIntNode.Value; // 返回 int 整型数值 + case NumberLongNode numberLongNode: // long整型数值字面量 + return numberLongNode.Value; // 返回 long 整型数值 + case NumberFloatNode numberFloatNode: // float浮点数值字面量 + return numberFloatNode.Value; // 返回 float 浮点数值 + case NumberDoubleNode numberDoubleNode: // double浮点数值字面量 + return numberDoubleNode.Value; // 返回 double 浮点数值 + #endregion + case IdentifierNode identifierNode: // 变量定义 + return context.GetVarValue(identifierNode.Name); + case IfNode ifNode: // if语句结构 + async Task InterpreterIfNodeAsync(IScriptInvokeContext context, IfNode ifNode) + { + var result = await InterpretAsync(context, ifNode.Condition) ?? throw new SereinSciptException(ifNode, $"条件语句返回了 null"); + if (result is not bool condition) throw new SereinSciptException(ifNode, "条件语句返回值不为 bool 类型"); + var branchNodes = condition ? ifNode.TrueBranch : ifNode.FalseBranch; + if (branchNodes.Count == 0) return default; + object? data = default; + foreach (var branchNode in branchNodes) { - throw new SereinSciptException(objectInstantiationNode, $"使用了未定义的类型\"{objectInstantiationNode.Type.TypeName}\""); + data = await InterpretAsync(context, branchNode); + if (branchNode is ReturnNode) // 遇到 Return 语句 提前退出 + { + context.IsNeedReturn = true; + break; + } + } + return data; + } + + return await InterpreterIfNodeAsync(context, ifNode); + case WhileNode whileNode: // while语句结构 + async Task InterpreterWhileNodeAsync(IScriptInvokeContext context, WhileNode whileNode) + { + object? data = default; + while (true) + { + var result = await InterpretAsync(context, whileNode.Condition) ?? throw new SereinSciptException(whileNode, $"循环节点条件返回了 null"); + if (result is not bool condition) throw new SereinSciptException(whileNode, "循环节点条件返回值不为 bool 类型"); + if (!condition) break; + if (whileNode.Body.Count == 0) break; + foreach (var node in whileNode.Body) + { + data = await InterpretAsync(context, node); + if (node is ReturnNode) // 遇到 Return 语句 提前退出 + { + context.IsNeedReturn = true; + break ; + } + } + } + return data; + } + await InterpreterWhileNodeAsync(context, whileNode); + return default; + case AssignmentNode assignmentNode: // 变量赋值语句 + async Task InterpreterAssignmentNodeAsync(IScriptInvokeContext context, AssignmentNode assignmentNode) + { + if (assignmentNode.Target is IdentifierNode identifierNode) + { + var value = await InterpretAsync(context, assignmentNode.Value); + context.SetVarValue(identifierNode.Name, value); } } - object?[] args = new object[objectInstantiationNode.Arguments.Count]; - for (int i = 0; i < objectInstantiationNode.Arguments.Count; i++) + await InterpreterAssignmentNodeAsync(context, assignmentNode); + return default; + case BinaryOperationNode binaryOperationNode: // 二元运算操作 + async Task InterpreterBinaryOperationNodeAsync(IScriptInvokeContext context, BinaryOperationNode binaryOperationNode) { - var argNode = objectInstantiationNode.Arguments[i]; - args[i] = await EvaluateAsync(context, argNode); + // 递归计算二元操作 + var left = await InterpretAsync(context, binaryOperationNode.Left); + if (left == null ) throw new SereinSciptException(binaryOperationNode.Left, $"左值尝试使用 null"); + var right = await InterpretAsync(context, binaryOperationNode.Right); + if (right == null) throw new SereinSciptException(binaryOperationNode.Right, "右值尝试使用计算 null"); + var op = binaryOperationNode.Operator; + var result = BinaryOperationEvaluator.EvaluateValue(left, op, right); + return result; } - var obj = Activator.CreateInstance(type, args: args);// 创建对象 - if (obj == null) + return await InterpreterBinaryOperationNodeAsync(context, binaryOperationNode); + case CollectionAssignmentNode collectionAssignmentNode: // 集合赋值节点 + async Task InterpreterCollectionAssignmentNodeAsync(IScriptInvokeContext context, CollectionAssignmentNode collectionAssignmentNode) { - throw new SereinSciptException(objectInstantiationNode, $"类型创建失败\"{objectInstantiationNode.Type.TypeName}\""); + var collectionValue = await InterpretAsync(context, collectionAssignmentNode.Collection.Collection); + if (collectionValue is null) + { + throw new ArgumentNullException($"解析{collectionAssignmentNode}节点时,集合返回空。"); + } + var indexValue = await InterpretAsync(context, collectionAssignmentNode.Collection.Index); + if (indexValue is null) + { + throw new ArgumentNullException($"解析{collectionAssignmentNode}节点时,索引返回空。"); + } + var valueValue = await InterpretAsync(context, collectionAssignmentNode.Value); + SetCollectionValue(collectionValue, indexValue, valueValue); } - for (int i = 0; i < objectInstantiationNode.CtorAssignments.Count; i++) + await InterpreterCollectionAssignmentNodeAsync(context, collectionAssignmentNode); + return default; + case CollectionIndexNode collectionIndexNode: // 集合获取索引对应值 + async Task InterpreterCollectionIndexNodeAsync(IScriptInvokeContext context, CollectionIndexNode collectionIndexNode) { - var ctorAssignmentNode = objectInstantiationNode.CtorAssignments[i]; - var propertyName = ctorAssignmentNode.MemberName; - var value = await EvaluateAsync(context, ctorAssignmentNode.Value); - SetPropertyValue(obj, propertyName, value); + var collectionValue = await InterpretAsync(context, collectionIndexNode.Collection); + if (collectionValue is null) + { + throw new ArgumentNullException($"解析{collectionIndexNode}节点时,集合返回空。"); + } + var indexValue = await InterpretAsync(context, collectionIndexNode.Index); + if (indexValue is null) + { + throw new ArgumentNullException($"解析{collectionIndexNode}节点时,索引返回空。"); + } + var result = GetCollectionValue(collectionValue, indexValue); + return result; } + return await InterpreterCollectionIndexNodeAsync(context, collectionIndexNode); + case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义 + void InterpreterClassTypeDefinitionNode(IScriptInvokeContext context, ClassTypeDefinitionNode classTypeDefinitionNode) + { + var className = classTypeDefinitionNode.ClassType.TypeName; + if (SereinScript.MountType.ContainsKey(className)) + { + //SereinEnv.WriteLine(InfoType.WARN, $"异常信息 : 类型重复定义,代码在第{classTypeDefinitionNode.Row}行: {classTypeDefinitionNode.Code.Trim()}"); + return; + } + if (DynamicObjectHelper.GetCacheType(className) == null) + { + var propertyTypes = classTypeDefinitionNode.Propertys.ToDictionary(p => p.Key, p => symbolInfos[p.Value]); + var type = DynamicObjectHelper.CreateTypeWithProperties(propertyTypes, className); // 实例化新的类型 + SereinScript.MountType[className] = type; // 定义对象 + } + } + InterpreterClassTypeDefinitionNode(context, classTypeDefinitionNode); + return default; + case TypeNode typeNode: // 类型 + return default; + case ObjectInstantiationNode objectInstantiationNode: // 类型实例化 + async Task InterpreterObjectInstantiationNodeAsync(IScriptInvokeContext context, ObjectInstantiationNode objectInstantiationNode) + { + if (!SereinScript.MountType.TryGetValue(objectInstantiationNode.Type.TypeName, out var type)) + { + type = symbolInfos[objectInstantiationNode.Type]; + if (type is null) + { + throw new SereinSciptException(objectInstantiationNode, $"使用了未定义的类型\"{objectInstantiationNode.Type.TypeName}\""); + } + } - return obj; - case FunctionCallNode callNode: // 调用方法 - return await InterpretFunctionCallAsync(context, callNode); // 调用方法返回函数的返回值 - case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用 - return await CallMemberFunction(context, memberFunctionCallNode); + // 获取参数 + var args = objectInstantiationNode.Arguments.Count == 0 ? [] : + (await objectInstantiationNode.Arguments.SelectAsync( + async argNode => await InterpretAsync(context, argNode))) + .ToArray(); + + var obj = Activator.CreateInstance(type, args: args);// 创建对象 + if (obj is null) + { + throw new SereinSciptException(objectInstantiationNode, $"类型创建失败\"{objectInstantiationNode.Type.TypeName}\""); + } + + for (int i = 0; i < objectInstantiationNode.CtorAssignments.Count; i++) + { + var ctorAssignmentNode = objectInstantiationNode.CtorAssignments[i]; + var propertyName = ctorAssignmentNode.MemberName; + var value = await InterpretAsync(context, ctorAssignmentNode.Value); + SetPropertyValue(obj, propertyName, value); + } + return obj; + } + return await InterpreterObjectInstantiationNodeAsync(context, objectInstantiationNode); + case CtorAssignmentNode ctorAssignmentNode: + return default; + case ExpressionNode expressionNode: // 类型表达式(链式调用) + return await InterpretAsync(context, expressionNode.Value); // 直接计算表达式的值 case MemberAccessNode memberAccessNode: // 对象成员访问 - return await GetMemberValue(context, memberAccessNode); - case CollectionIndexNode collectionIndexNode: - return await GetCollectionValue(context, collectionIndexNode); - case ReturnNode returnNode: // 返回内容 - return await EvaluateAsync(context, returnNode.Value); // 直接返回响应的内容 - case ExpressionNode expressionNode: // 表达式 - return await EvaluateAsync(context, expressionNode.Value); - default: - throw new SereinSciptException(node, $"解释器 EvaluateAsync() 未实现{node}节点行为"); - } - } + async Task InterpreterMemberAccessNodeAsync(IScriptInvokeContext context, MemberAccessNode memberAccessNode) + { + var target = await InterpretAsync(context, memberAccessNode.Object); + var memberName = memberAccessNode.MemberName; + if(target is null) throw new SereinSciptException(memberAccessNode, $"无法获取成员,对象为 null \"{memberAccessNode.Object.Code}\""); + var value = GetPropertyValue(target, memberName); + return value; + } + return await InterpreterMemberAccessNodeAsync(context, memberAccessNode); + case MemberAssignmentNode memberAssignmentNode: // 对象成员赋值 + async Task InterpreterMemberAssignmentNodeAsync(IScriptInvokeContext context, MemberAssignmentNode memberAssignmentNode) + { + var target = await InterpretAsync(context, memberAssignmentNode.Object); + var memberName = memberAssignmentNode.MemberName; + var value = await InterpretAsync(context, memberAssignmentNode.Value); + if (target is null) throw new SereinSciptException(memberAssignmentNode, $"无法设置成员,对象为 null \"{memberAssignmentNode.Object.Code}\""); + SetPropertyValue(target, memberName, value); + return value; + } + return await InterpreterMemberAssignmentNodeAsync(context, memberAssignmentNode); + case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用 + async Task InterpreterMemberFunctionCallNodeAsync(IScriptInvokeContext context, MemberFunctionCallNode memberFunctionCallNode) + { + var target = await InterpretAsync(context, memberFunctionCallNode.Object); + if (!MethodNodeDelegateCaches.TryGetValue(memberFunctionCallNode, out DelegateDetails? delegateDetails)) + { + var methodName = memberFunctionCallNode.FunctionName; + var methodInfo = memberFunctionCallNode.Arguments.Count == 0 ? target?.GetType().GetMethod(methodName, []) : target?.GetType().GetMethod(methodName);// 获取参数列表的类型 + if (methodInfo is null) throw new SereinSciptException(memberFunctionCallNode, $"对象没有方法\"{memberFunctionCallNode.FunctionName}\""); + delegateDetails = new DelegateDetails(methodInfo); + MethodNodeDelegateCaches[memberFunctionCallNode] = delegateDetails; + } // 查询是否有缓存 - private object EvaluateBinaryOperation(object left, string op, object right) - { - return BinaryOperationEvaluator.EvaluateValue(left, op, right); - // 根据运算符执行不同的运算 - switch (op) - { - case "+": - if (left is string || right is string) - { - return left?.ToString() + right?.ToString(); // 字符串拼接 - } - else if (left is int leftInt && right is int rightInt) - { - return leftInt + rightInt; // 整数加法 - } - else if (left is long leftLong && right is long rightLong) - { - return leftLong + rightLong; // 整数加法 - } - else if (left is double leftDouble && right is double rightDouble) - { - return leftDouble + rightDouble; // 整数加法 - } - else - { - dynamic leftValue = Convert.ToDouble(left); - dynamic rightValue = Convert.ToDouble(right); - return leftValue + rightValue; - } - throw new Exception("Invalid types for + operator"); - case "-": - return (int)left - (int)right; - case "*": - return (int)left * (int)right; - case "/": - return (int)left / (int)right; + // 获取参数 + var arguments = memberFunctionCallNode.Arguments.Count == 0 ? [] : + (await memberFunctionCallNode.Arguments.SelectAsync( + async argNode => await InterpretAsync(context, argNode))) + .ToArray(); - case ">": - return (int)left > (int)right; - case "<": - return (int)left < (int)right; - case "==": - return Equals(left, right); - case "!=": - return !Equals(left, right); + // 调用方法 + var reuslt = await delegateDetails.InvokeAsync(target, arguments); + return reuslt; + } + return await InterpreterMemberFunctionCallNodeAsync(context, memberFunctionCallNode); + case FunctionCallNode functionCallNode: // 外部挂载的函数调用 + async Task InterpreterFunctionCallNodeAsync(IScriptInvokeContext context, FunctionCallNode functionCallNode) + { + // 获取流程上下文 + if (functionCallNode.FunctionName.Equals("getFlowApi", StringComparison.OrdinalIgnoreCase)) + { + return context.FlowContext; + } + else if (functionCallNode.FunctionName.Equals("getScriptApi", StringComparison.OrdinalIgnoreCase)) + { + return context; + } - default: - throw new NotImplementedException("未定义的操作符: " + op); + // 获取参数 + var arguments = functionCallNode.Arguments.Count == 0 ? [] : + (await functionCallNode.Arguments.SelectAsync( + async argNode => await InterpretAsync(context, argNode))) + .ToArray(); + + + var funcName = functionCallNode.FunctionName; + + object? instance = null; // 静态方法不需要传入实例,所以可以传入null + + // 查找并执行对应的函数 + if (!SereinScript.FunctionDelegates.TryGetValue(funcName, out DelegateDetails? function)) + throw new SereinSciptException(functionCallNode, $"没有挂载方法\"{functionCallNode.FunctionName}\""); + + if (!function.EmitMethodInfo.IsStatic) + { + if (!SereinScript.DelegateInstances.TryGetValue(funcName, out var action)) + { + throw new SereinSciptException(functionCallNode, $"挂载方法 {funcName} 时需要同时给定获取实例的 Func"); + } + + instance = action.Invoke();// 非静态的方法需要获取相应的实例 + if (instance is null) + { + throw new SereinSciptException(functionCallNode, $"函数 {funcName} 尝试获取实例时返回了 null "); + } + } + + var result = await function.InvokeAsync(instance, arguments); + return result; + } + return await InterpreterFunctionCallNodeAsync(context, functionCallNode); + default: // 未定义的节点类型 + throw new Exception($"解释器未实现的节点类型 {node.GetType()}"); } } @@ -449,54 +346,11 @@ namespace Serein.Script /// /// 设置对象成员 /// - /// - /// - /// - public async Task SetMemberValue(IScriptInvokeContext context, MemberAssignmentNode memberAssignmentNode) - { - var target = await EvaluateAsync(context, memberAssignmentNode.Object); - var value = await EvaluateAsync(context, memberAssignmentNode.Value); - // 设置值 - var lastMember = memberAssignmentNode.MemberName; - - var lastProperty = target?.GetType().GetProperty(lastMember); - if (lastProperty is null) - { - var lastField = target?.GetType().GetRuntimeField(lastMember); - if (lastField is null) - { - throw new SereinSciptException(memberAssignmentNode, $"对象没有成员\"{memberAssignmentNode.MemberName}\""); - } - else - { - var convertedValue = Convert.ChangeType(value, lastField.FieldType); - lastField.SetValue(target, convertedValue); - } - } - else - { - if(value is null) - { - lastProperty.SetValue(target, null); - return; - } - var valueTtpe = value.GetType(); - if (lastProperty.PropertyType.IsAssignableFrom(valueTtpe)) - { - lastProperty.SetValue(target, value); - } - else if (lastProperty.PropertyType.FullName == valueTtpe.FullName) - { - lastProperty.SetValue(target, value); - } - else { - throw new SereinSciptException(memberAssignmentNode, $"对象成员赋值时类型异常:\"{memberAssignmentNode.MemberName}\""); - } - //var convertedValue = Convert.ChangeType(value, ); - } - } - - public void SetPropertyValue(object target, string memberName, object? value) + /// 对象 + /// 属性名称 + /// 属性值 + /// + private void SetPropertyValue(object target, string memberName, object? value) { var targetType = target?.GetType(); if (targetType is null) return; @@ -534,132 +388,49 @@ namespace Serein.Script { throw new Exception($"类型 {targetType} 对象成员\"{memberName}\" 赋值时异常"); } - //var convertedValue = Convert.ChangeType(value, ); } } /// - /// 获取对象成员 + /// 从对象获取值 /// - /// + /// 对象 + /// 成员名称 /// - /// - public async Task GetMemberValue(IScriptInvokeContext context, MemberAccessNode memberAccessNode) + /// + private object? GetPropertyValue(object target, string memberName) { - var target = await EvaluateAsync(context, memberAccessNode.Object); - var lastMember = memberAccessNode.MemberName; - - var lastProperty = target?.GetType().GetProperty(lastMember); - if (lastProperty is null) + var targetType = target?.GetType(); + if (targetType is null) return null; + var propertyInfo = targetType.GetProperty(memberName); + if (propertyInfo is null) { - var lastField = target?.GetType().GetRuntimeField(lastMember); - if (lastField is null) + var fieldInfo = target?.GetType().GetRuntimeField(memberName); + if (fieldInfo is null) { - throw new SereinSciptException(memberAccessNode, $"对象没有成员\"{memberAccessNode.MemberName}\""); + throw new Exception($"类型 {targetType} 对象没有成员\"{memberName}\""); } else { - return lastField.GetValue(target); + return fieldInfo.GetValue(target); } } else { - return lastProperty.GetValue(target); + return propertyInfo.GetValue(target); } } - + /// - /// 获取集合中的成员 + /// 设置集合成员 /// - /// + /// + /// + /// /// - /// - public async Task GetCollectionValue(IScriptInvokeContext context, CollectionIndexNode collectionIndexNode) + /// + private void SetCollectionValue(object collectionValue, object indexValue, object valueValue) { - var target = await EvaluateAsync(context, collectionIndexNode.Collection); // 获取对象 - if (target is null) - { - throw new ArgumentNullException($"解析{collectionIndexNode}节点时,TargetValue返回空。"); - } - - // 解析数组/集合名与索引部分 - var targetType = target.GetType(); // 目标对象的类型 - #region 处理键值对 - if (targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Dictionary<,>)) - { - // 目标是键值对 - var method = targetType.GetMethod("get_Item", BindingFlags.Public | BindingFlags.Instance); - if (method is not null) - { - var key = await EvaluateAsync(context, collectionIndexNode.Index); // 获取索引值; - var result = method.Invoke(target, new object[] { key }); - return result; - } - } - #endregion - #region 处理集合对象 - else - { - var indexValue = await EvaluateAsync(context, collectionIndexNode.Index); // 获取索引值 - object? result; - if (indexValue is int index) - { - // 获取数组或集合对象 - // 访问数组或集合中的指定索引 - if (target is Array array) - { - if (index < 0 || index >= array.Length) - { - throw new ArgumentException($"解析{collectionIndexNode}节点时,数组下标越界。"); - } - result = array.GetValue(index); - return result; - } - else if (target is IList list) - { - if (index < 0 || index >= list.Count) - { - throw new ArgumentException($"解析{collectionIndexNode}节点时,数组下标越界。"); - } - result = list[index]; - return result; - } - else if (target is string chars) - { - return chars[index]; - } - else - { - throw new ArgumentException($"解析{collectionIndexNode}节点时,左值并非有效集合。"); - } - } - } - #endregion - - throw new ArgumentException($"解析{collectionIndexNode}节点时,左值并非有效集合。"); - - } - - /// - /// 设置集合中的成员 - /// - /// - /// - /// - public async Task SetCollectionValue(IScriptInvokeContext context, CollectionAssignmentNode collectionAssignmentNode) - { - var collectionValue = await EvaluateAsync(context, collectionAssignmentNode.Collection.Collection); - var indexValue = await EvaluateAsync(context, collectionAssignmentNode.Collection.Index); - - if (collectionValue is null) - { - throw new ArgumentNullException($"解析{collectionAssignmentNode}节点时,集合返回空。"); - } - if (indexValue is null) - { - throw new ArgumentNullException($"解析{collectionAssignmentNode}节点时,索引返回空。"); - } - // 解析数组/集合名与索引部分 var targetType = collectionValue.GetType(); // 目标对象的类型 #region 处理键值对 @@ -669,7 +440,6 @@ namespace Serein.Script var method = targetType.GetMethod("set_Item", BindingFlags.Public | BindingFlags.Instance); if (method is not null) { - var valueValue = await EvaluateAsync(context, collectionAssignmentNode.Value); method.Invoke(collectionValue, [indexValue, valueValue]); } } @@ -687,7 +457,6 @@ namespace Serein.Script { throw new ArgumentException($"解析{collectionValue}节点时,数组下标越界。"); } - var valueValue = await EvaluateAsync(context, collectionAssignmentNode.Value); array.SetValue(valueValue, index); return; } @@ -697,77 +466,67 @@ namespace Serein.Script { throw new ArgumentException($"解析{collectionValue}节点时,数组下标越界。"); } - var valueValue = await EvaluateAsync(context, collectionAssignmentNode.Value); list[index] = valueValue; return; } - else + } + } + #endregion + throw new ArgumentException($"解析异常, {collectionValue} 并非有效集合。"); + } + + /// + /// 获取集合中的成员 + /// + /// + /// + /// + /// + private object? GetCollectionValue(object collectionValue, object indexValue) + { + // 解析数组/集合名与索引部分 + var targetType = collectionValue.GetType(); // 目标对象的类型 + #region 处理键值对 + if (targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Dictionary<,>)) + { + // 目标是键值对 + var method = targetType.GetMethod("get_Item", BindingFlags.Public | BindingFlags.Instance); + if (method is not null) + { + var value = method.Invoke(collectionValue, [indexValue]); + return value; + } + } + #endregion + #region 处理集合对象 + else + { + if (indexValue is int index) + { + // 获取数组或集合对象 + // 访问数组或集合中的指定索引 + if (collectionValue is Array array) { - throw new ArgumentException($"解析{collectionValue}节点时,左值并非有效集合。"); + if (index < 0 || index >= array.Length) + { + throw new ArgumentException($"解析{collectionValue}节点时,数组下标越界。"); + } + + return array.GetValue(index); + } + else if (collectionValue is IList list) + { + if (index < 0 || index >= list.Count) + { + throw new ArgumentException($"解析{collectionValue}节点时,数组下标越界。"); + } + return list[index]; } } } #endregion throw new ArgumentException($"解析{collectionValue}节点时,左值并非有效集合。"); - - } - - /// - /// 缓存method委托 - /// - private Dictionary MethodToDelegateCaches { get; } = new Dictionary(); - - public async Task CallMemberFunction(IScriptInvokeContext context, MemberFunctionCallNode memberFunctionCallNode) - { - var target = await EvaluateAsync(context, memberFunctionCallNode.Object); - var lastMember = memberFunctionCallNode.FunctionName; - if(lastMember == "ToUpper") - { - - } - MethodInfo? methodInfo = null; - if (memberFunctionCallNode.Arguments.Count == 0) - { - - // 查询无参方法 - methodInfo = target?.GetType().GetMethod(lastMember, []) ?? throw new SereinSciptException(memberFunctionCallNode, $"对象没有方法\"{memberFunctionCallNode.FunctionName}\""); - } - else - { - // 获取参数列表的类型 - methodInfo = target?.GetType().GetMethod(lastMember) ?? throw new SereinSciptException(memberFunctionCallNode, $"对象没有方法\"{memberFunctionCallNode.FunctionName}\""); - - } - - /*Type[] paramTypes = new - { - - }*/ - - if (!MethodToDelegateCaches.TryGetValue(methodInfo.MetadataToken, out DelegateDetails? delegateDetails)) - { - delegateDetails = new DelegateDetails(methodInfo); - MethodToDelegateCaches[methodInfo.MetadataToken] = delegateDetails; - } - - if(memberFunctionCallNode.Arguments.Count == 0) - { - var reuslt = await delegateDetails.InvokeAsync(target, []); - return reuslt; - } - else - { - var arguments = new object?[memberFunctionCallNode.Arguments.Count]; - for (int i = 0; i < memberFunctionCallNode.Arguments.Count; i++) - { - ASTNode? arg = memberFunctionCallNode.Arguments[i]; - arguments[i] = await EvaluateAsync(context, arg); // 评估每个参数 - } - var reuslt = await delegateDetails.InvokeAsync(target, arguments); - return reuslt; - } - } diff --git a/Serein.Script/SereinScriptLexer.cs b/Serein.Script/SereinScriptLexer.cs index 9a5a2a7..862ceca 100644 --- a/Serein.Script/SereinScriptLexer.cs +++ b/Serein.Script/SereinScriptLexer.cs @@ -198,7 +198,6 @@ namespace Serein.Script this._index = token.StartIndex; } - internal Token NextToken() { @@ -525,7 +524,6 @@ namespace Serein.Script return ReadOnlySpan.Empty; } - public int GetIndex() { return _index; diff --git a/Serein.Script/SereinScriptTypeAnalysis.cs b/Serein.Script/SereinScriptTypeAnalysis.cs index d73776f..15d5810 100644 --- a/Serein.Script/SereinScriptTypeAnalysis.cs +++ b/Serein.Script/SereinScriptTypeAnalysis.cs @@ -75,7 +75,6 @@ namespace Serein.Script } - /// /// 类型获取 /// @@ -542,6 +541,8 @@ namespace Serein.Script break; case ObjectInstantiationNode objectInstantiationNode: // 类型实例化 break; + case CtorAssignmentNode ctorAssignmentNode: + break; case ExpressionNode expressionNode: // 类型表达式(链式调用) break; case MemberAccessNode memberAccessNode: // 对象成员访问