diff --git a/Library/FlowNode/MethodDetails.cs b/Library/FlowNode/MethodDetails.cs index d407fdd..340f69d 100644 --- a/Library/FlowNode/MethodDetails.cs +++ b/Library/FlowNode/MethodDetails.cs @@ -292,7 +292,7 @@ namespace Serein.Library /// 从DLL拖动出来时,从元数据拷贝新的实例,作为属于节点独享的方法描述 /// /// - public MethodDetails CloneOfNode( IFlowNode nodeModel) + public MethodDetails CloneOfNode(IFlowNode nodeModel) { // this => 是元数据 var md = new MethodDetails(nodeModel) // 创建新节点时拷贝实例 diff --git a/NodeFlow/Env/FlowControl.cs b/NodeFlow/Env/FlowControl.cs index 9b37153..cebe6a5 100644 --- a/NodeFlow/Env/FlowControl.cs +++ b/NodeFlow/Env/FlowControl.cs @@ -48,11 +48,7 @@ namespace Serein.NodeFlow.Env /// private RunState FlipFlopState = RunState.NoStart; - - /// - /// 异步运行 - /// - /// + /// public async Task StartFlowAsync(string[] canvasGuids) { #region 校验参数 @@ -144,12 +140,7 @@ namespace Serein.NodeFlow.Env return true; } - - /// - /// 从选定节点开始运行 - /// - /// - /// + /// public async Task StartFlowAsync(string startNodeGuid) { @@ -207,10 +198,7 @@ namespace Serein.NodeFlow.Env } return result; }*/ - - /// - /// 结束流程 - /// + /// public Task ExitFlowAsync() { flowWorkManagement?.Exit(); @@ -220,11 +208,7 @@ namespace Serein.NodeFlow.Env GC.Collect(); return Task.FromResult(true); } - - /// - /// 激活全局触发器 - /// - /// + /// public void ActivateFlipflopNode(string nodeGuid) { /*if (!TryGetNodeModel(nodeGuid, out var nodeModel)) @@ -242,11 +226,7 @@ namespace Serein.NodeFlow.Env } }*/ } - - /// - /// 关闭全局触发器 - /// - /// + /// public void TerminateFlipflopNode(string nodeGuid) { /* if (!TryGetNodeModel(nodeGuid, out var nodeModel)) @@ -264,24 +244,12 @@ namespace Serein.NodeFlow.Env { this.sereinIOC = ioc; // 设置IOC容器 } - - /// - /// 启动器调用,运行到某个节点时触发了监视对象的更新(对象预览视图将会自动更新) - /// - /// - /// - /// + /// public void MonitorObjectNotification(string nodeGuid, object monitorData, MonitorObjectEventArgs.ObjSourceType sourceType) { flowEnvironmentEvent.OnMonitorObjectChanged(new MonitorObjectEventArgs(nodeGuid, monitorData, sourceType)); } - - /// - /// 启动器调用,节点触发了中断。 - /// - /// 节点 - /// 表达式 - /// 类型,0用户主动的中断,1表达式中断 + /// public void TriggerInterrupt(string nodeGuid, string expression, InterruptTriggerEventArgs.InterruptTriggerType type) { flowEnvironmentEvent.OnInterruptTriggered(new InterruptTriggerEventArgs(nodeGuid, expression, type)); @@ -292,28 +260,14 @@ namespace Serein.NodeFlow.Env #region 流程接口调用 - - /// - /// 调用流程接口,将返回 FlowResult.Value。如果需要 FlowResult 对象,请使用该方法的泛型版本。 - /// - /// 流程接口节点Guid - /// 调用时入参参数 - /// + /// public async Task InvokeAsync(string apiGuid, Dictionary dict) { var result = await InvokeAsync(apiGuid, dict); return result; } - - /// - /// 调用流程接口,泛型类型为 FlowResult 时,将返回 FlowResult 对象。 - /// - /// - /// 流程接口节点Guid - /// 调用时入参参数 - /// - /// + /// public async Task InvokeAsync(string apiGuid, Dictionary dict) { if (sereinIOC is null) diff --git a/NodeFlow/Env/FlowEdit.cs b/NodeFlow/Env/FlowEdit.cs index f245b14..992af53 100644 --- a/NodeFlow/Env/FlowEdit.cs +++ b/NodeFlow/Env/FlowEdit.cs @@ -201,7 +201,7 @@ namespace Serein.NodeFlow.Env private int _add_canvas_count = 1; - + /// public void CreateCanvas(string canvasName, int width, int height) { IOperation operation = new CreateCanvasOperation @@ -219,7 +219,7 @@ namespace Serein.NodeFlow.Env flowOperationService.Execute(operation); } - + /// public void RemoveCanvas(string canvasGuid) { IOperation operation = new RemoveCanvasOperation @@ -228,7 +228,7 @@ namespace Serein.NodeFlow.Env }; flowOperationService.Execute(operation); } - + /// public void ConnectInvokeNode(string canvasGuid, string fromNodeGuid, string toNodeGuid, JunctionType fromNodeJunctionType, JunctionType toNodeJunctionType, ConnectionInvokeType invokeType) { IOperation operation = new ChangeNodeConnectionOperation @@ -245,7 +245,7 @@ namespace Serein.NodeFlow.Env flowOperationService.Execute(operation); } - + /// public void ConnectArgSourceNode(string canvasGuid, string fromNodeGuid, string toNodeGuid, JunctionType fromNodeJunctionType, JunctionType toNodeJunctionType, ConnectionArgSourceType argSourceType, int argIndex) { IOperation operation = new ChangeNodeConnectionOperation @@ -262,7 +262,7 @@ namespace Serein.NodeFlow.Env }; flowOperationService.Execute(operation); } - + /// public void RemoveInvokeConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType) { IOperation operation = new ChangeNodeConnectionOperation @@ -276,7 +276,7 @@ namespace Serein.NodeFlow.Env }; flowOperationService.Execute(operation); } - + /// public void RemoveArgSourceConnect(string canvasGuid, string fromNodeGuid, string toNodeGuid, int argIndex) { IOperation operation = new ChangeNodeConnectionOperation @@ -290,7 +290,7 @@ namespace Serein.NodeFlow.Env }; flowOperationService.Execute(operation); } - + /// public void CreateNode(string canvasGuid, NodeControlType nodeType, PositionOfUI position, MethodDetailsInfo methodDetailsInfo = null) { IOperation operation = new CreateNodeOperation @@ -302,7 +302,7 @@ namespace Serein.NodeFlow.Env }; flowOperationService.Execute(operation); } - + /// public void RemoveNode(string canvasGuid, string nodeGuid) { IOperation operation = new RemoveNodeOperation @@ -312,7 +312,7 @@ namespace Serein.NodeFlow.Env }; flowOperationService.Execute(operation); } - + /// public void PlaceNodeToContainer(string canvasGuid, string nodeGuid, string containerNodeGuid) { IOperation operation = new ContainerPlaceNodeOperation @@ -323,7 +323,7 @@ namespace Serein.NodeFlow.Env }; flowOperationService.Execute(operation); } - + /// public void TakeOutNodeToContainer(string canvasGuid, string nodeGuid) { IOperation operation = new ContainerTakeOutNodeOperation @@ -333,7 +333,7 @@ namespace Serein.NodeFlow.Env }; flowOperationService.Execute(operation); } - + /// public void SetStartNode(string canvasGuid, string nodeGuid) { @@ -363,7 +363,7 @@ namespace Serein.NodeFlow.Env )); return; } - + /// public void SetConnectPriorityInvoke(string fromNodeGuid, string toNodeGuid, ConnectionInvokeType connectionType) { @@ -377,7 +377,7 @@ namespace Serein.NodeFlow.Env }; flowOperationService.Execute(operation); } - + /// public void ChangeParameter(string nodeGuid, bool isAdd, int paramIndex) { IOperation operation = new ChangeParameterOperation @@ -389,12 +389,7 @@ namespace Serein.NodeFlow.Env flowOperationService.Execute(operation); } - /// - /// 从节点信息集合批量加载节点控件 - /// - /// 节点信息 - /// - /// + /// public async Task LoadNodeInfosAsync(List nodeInfos) { #region 从NodeInfo创建NodeModel @@ -635,11 +630,7 @@ namespace Serein.NodeFlow.Env #region 视觉效果 - - /// - /// 定位节点 - /// - /// + /// public void NodeLocate(string nodeGuid) { if (OperatingSystem.IsWindows()) diff --git a/NodeFlow/Model/Node/SingleFlowCallNode.cs b/NodeFlow/Model/Node/SingleFlowCallNode.cs index 9440e00..18ef262 100644 --- a/NodeFlow/Model/Node/SingleFlowCallNode.cs +++ b/NodeFlow/Model/Node/SingleFlowCallNode.cs @@ -85,43 +85,47 @@ namespace Serein.NodeFlow.Model TargetNodeGuid = nodeGuid; } + + /// + /// 目标节点发生改变 + /// + /// partial void OnTargetNodeGuidChanged(string value) { if (string.IsNullOrEmpty(value) || !Env.TryGetNodeModel(value, out var targetNode)) { // 取消设置接口节点 - TargetNode.PropertyChanged -= TargetNode_PropertyChanged; + TargetNode.PropertyChanged -= TargetNode_PropertyChanged; // 不再监听目标属通知 TargetNode = null; this.ApiGlobalName = ""; this.MethodDetails = new MethodDetails(); } else { - //if (this.MethodDetails.ActingInstanceType.FullName.Equals()) TargetNode = targetNode; - if (!this.IsShareParam - && CacheMethodDetails is not null - && TargetNode.MethodDetails is not null - && TargetNode.MethodDetails.AssemblyName == CacheMethodDetails.AssemblyName - && TargetNode.MethodDetails.MethodName == CacheMethodDetails.MethodName) + if (!this.IsShareParam // 不共享参数 + && TargetNode.MethodDetails is not null // 目标节点有方法描述 + && CacheMethodDetails is not null // 存在缓存 + && TargetNode.MethodDetails.AssemblyName == CacheMethodDetails.AssemblyName // 与缓存中一致 + && TargetNode.MethodDetails.MethodName == CacheMethodDetails.MethodName) // 与缓存中一致 { - this.MethodDetails = CacheMethodDetails; - this.ApiGlobalName = GetApiInvokeName(this); + this.MethodDetails = CacheMethodDetails; // 直接使用缓存 + this.ApiGlobalName = GetApiInvokeName(this); // 生成新的接口名称 } else { - if (TargetNode.MethodDetails is not null) + if (TargetNode.MethodDetails is not null) // // 目标节点有方法描述 { - CacheMethodDetails = TargetNode.MethodDetails.CloneOfNode(this); // 从目标节点复制一份 - TargetNode.PropertyChanged += TargetNode_PropertyChanged; - this.MethodDetails = CacheMethodDetails; - this.ApiGlobalName = GetApiInvokeName(this); + CacheMethodDetails = TargetNode.MethodDetails.CloneOfNode(this); // 从目标节点复制一份到缓存中 + TargetNode.PropertyChanged += TargetNode_PropertyChanged; // 监听目标属性通知(“IsPublic”属性) + this.MethodDetails = CacheMethodDetails; // 设置流程接口节点的方法描述为目标节点的方法描述(共享参数更改) + this.ApiGlobalName = GetApiInvokeName(this); // 生成新的接口名称 } } } - OnPropertyChanged(nameof(MethodDetails)); + OnPropertyChanged(nameof(MethodDetails)); // 通知控件,MethodDetails属性发生改变 } partial void OnIsShareParamChanged(bool value) @@ -132,6 +136,7 @@ namespace Serein.NodeFlow.Model } if (value) { + // 不再与目标节点共享参数,而是拷贝新的实体,缓存起来,自己单独使用 CacheMethodDetails = TargetNode.MethodDetails.CloneOfNode(this); this.MethodDetails = CacheMethodDetails; } @@ -140,13 +145,18 @@ namespace Serein.NodeFlow.Model if(TargetNode.ControlType == NodeControlType.Script) { - // 脚本节点入参需不可编辑入参数量、入参名称 + // 限制脚本节点对于入参数量、入参名称的修改 foreach (var item in CacheMethodDetails.ParameterDetailss) { item.IsParams = false; } } - this.MethodDetails = CacheMethodDetails; + // 与目标节点共享参数 + if(CacheMethodDetails is null) + { + CacheMethodDetails = TargetNode.MethodDetails; // 防御性代码,几乎不可能触发 + } + this.MethodDetails = CacheMethodDetails; } OnPropertyChanged(nameof(MethodDetails)); diff --git a/NodeFlow/Model/Node/SingleScriptNode.cs b/NodeFlow/Model/Node/SingleScriptNode.cs index 9da230c..0336c3b 100644 --- a/NodeFlow/Model/Node/SingleScriptNode.cs +++ b/NodeFlow/Model/Node/SingleScriptNode.cs @@ -2,7 +2,7 @@ using Serein.Library.Api; using Serein.Library.Utils; using Serein.Script; -using Serein.Script.Node; +using Serein.Script.Node.FlowControl; using System; using System.Collections.Generic; using System.Dynamic; @@ -35,7 +35,7 @@ namespace Serein.NodeFlow.Model private IScriptFlowApi ScriptFlowApi; private ProgramNode programNode; - private SereinScriptInterpreter ScriptInterpreter; + private readonly SereinScriptInterpreter scriptInterpreter; private bool IsScriptChanged = false; /// @@ -45,7 +45,7 @@ namespace Serein.NodeFlow.Model public SingleScriptNode(IFlowEnvironment environment):base(environment) { ScriptFlowApi = new ScriptFlowApi(environment, this); - ScriptInterpreter = new SereinScriptInterpreter(); + scriptInterpreter = new SereinScriptInterpreter(); } static SingleScriptNode() @@ -79,11 +79,11 @@ namespace Serein.NodeFlow.Model /// public override void OnCreating() { - MethodInfo? method = this.GetType().GetMethod(nameof(GetFlowApi)); + /* MethodInfo? method = this.GetType().GetMethod(nameof(GetFlowApi)); if (method != null) { ScriptInterpreter.AddFunction(nameof(GetFlowApi), method, () => this); // 挂载获取流程接口 - } + }*/ var md = MethodDetails; var pd = md.ParameterDetailss ??= new ParameterDetails[1]; @@ -103,8 +103,8 @@ namespace Serein.NodeFlow.Model Items = null, IsParams = true, //Description = "脚本节点入参" - }; + md.ReturnType = typeof(object); // 默认返回 object } @@ -157,19 +157,24 @@ namespace Serein.NodeFlow.Model varNames.Add(pd.Name); } - var sb = new StringBuilder(); + /*var sb = new StringBuilder(); foreach (var pd in MethodDetails.ParameterDetailss) { sb.AppendLine($"let {pd.Name};"); // 提前声明这些变量 } sb.Append(Script); - var script = sb.ToString(); - var p = new SereinScriptParser(script); - //var p = new SereinScriptParser(Script); - programNode = p.Parse(); // 开始解析 - var typeAnalysis = new SereinScriptTypeAnalysis(); - ScriptInterpreter.SetTypeAnalysis(typeAnalysis); - typeAnalysis.AnalysisProgramNode(programNode); + var script = sb.ToString();*/ + var parser = new SereinScriptParser(); // 准备解析器 + var typeAnalysis = new SereinScriptTypeAnalysis(); // 准备分析器 + programNode = parser.Parse(Script); // 开始解析获取程序主节点 + + 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]; // 获取返回类型 + MethodDetails.ReturnType = returnType; + //scriptInterpreter.SetTypeAnalysis(typeAnalysis); // 设置类型分析器 } catch (Exception ex) @@ -240,17 +245,17 @@ namespace Serein.NodeFlow.Model if (token.IsCancellationRequested) return null; - var result = await ScriptInterpreter.InterpretAsync(scriptContext, programNode); // 从入口节点执行 + var result = await scriptInterpreter.InterpretAsync(scriptContext, programNode); // 从入口节点执行 envEvent.FlowRunComplete -= onFlowStop; return new FlowResult(this.Guid, context, result); } #region 挂载的方法 - public IScriptFlowApi GetFlowApi() + /*public IScriptFlowApi GetFlowApi() { return ScriptFlowApi; - } + }*/ private static class ScriptBaseFunc { diff --git a/NodeFlow/Model/Operation/ChangeNodeConnectionOperation.cs b/NodeFlow/Model/Operation/ChangeNodeConnectionOperation.cs index d4b2627..a47f4d1 100644 --- a/NodeFlow/Model/Operation/ChangeNodeConnectionOperation.cs +++ b/NodeFlow/Model/Operation/ChangeNodeConnectionOperation.cs @@ -375,13 +375,28 @@ namespace Serein.NodeFlow.Model.Operation $"{Environment.NewLine}目标节点:{ToNode.Guid}"); return false; }*/ + + if (FromNode.MethodDetails.ReturnType == typeof(void)) + { + SereinEnv.WriteLine(InfoType.WARN, $"连接失败,节点参数入参不允许接收 void 返回值"); + return false; + } + + var toNodeArgSourceGuid = ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid; // 目标节点对应参数可能已经有其它连接 var toNodeArgSourceType = ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceType; - - if (FromNode.Guid == toNodeArgSourceGuid - && toNodeArgSourceType == ConnectionArgSourceType) + + if (false && string.IsNullOrWhiteSpace(toNodeArgSourceGuid) && flowModelService.ContainsNodeModel(toNodeArgSourceGuid)) { - if (FromNode.NeedResultNodes[type].Contains(ToNode)) + SereinEnv.WriteLine(InfoType.WARN, $"连接失败,节点参数入参不允许接收多个节点返回值"); + return false; + } + + + // 判断是否建立过连接关系 + if (FromNode.Guid == toNodeArgSourceGuid && toNodeArgSourceType == ConnectionArgSourceType) + { + if (FromNode.NeedResultNodes[type].Contains(ToNode)) // 如果来源节点被该节点获取过,则创建链接 { SereinEnv.WriteLine(InfoType.INFO, $"节点之间已建立过连接关系" + $"起始节点:{FromNode.Guid}" + @@ -390,14 +405,18 @@ namespace Serein.NodeFlow.Model.Operation $"参数类型:{ConnectionArgSourceType}"); return false; } + + var fromNodeGuid = FromNode.Guid; + var toNodeGuid = ToNode.Guid; + // 目标节点需要参数,但却没有被依赖的记录,则添加依赖记录并出现连接 FromNode.NeedResultNodes[type].Add(ToNode); await TriggerEvent(() => { flowEnvironmentEvent.OnNodeConnectChanged( new NodeConnectChangeEventArgs( FlowCanvas.Guid, - FromNode.Guid, // 从哪个节点开始 - ToNode.Guid, // 连接到那个节点 + fromNodeGuid, // 从哪个节点开始 + toNodeGuid, // 连接到那个节点 ArgIndex, // 连接线的样式类型 JunctionOfConnectionType.Arg, ConnectionArgSourceType, @@ -409,8 +428,8 @@ namespace Serein.NodeFlow.Model.Operation flowEnvironmentEvent.OnNodeConnectChanged( new NodeConnectChangeEventArgs( FlowCanvas.Guid, - FromNode.Guid, // 从哪个节点开始 - ToNode.Guid, // 连接到那个节点 + fromNodeGuid, // 从哪个节点开始 + toNodeGuid, // 连接到那个节点 ArgIndex, // 连接线的样式类型 JunctionOfConnectionType.Arg, ConnectionArgSourceType, @@ -421,18 +440,20 @@ namespace Serein.NodeFlow.Model.Operation return true; } - if (!string.IsNullOrEmpty(toNodeArgSourceGuid)) // 更改关系获取 + if (!string.IsNullOrEmpty(toNodeArgSourceGuid)) // 参数入参节点已有来源,更改节点参数来源 { + var fromNodeGuid = ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid; + var toNodeGuid = ToNode.Guid; ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid = null; ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceType = ConnectionArgSourceType.GetPreviousNodeData; // 恢复默认值 - + FromNode.NeedResultNodes[type].Remove(ToNode); await TriggerEvent(() => { flowEnvironmentEvent.OnNodeConnectChanged( new NodeConnectChangeEventArgs( FlowCanvas.Guid, - FromNode.Guid, - ToNode.Guid, + fromNodeGuid, + toNodeGuid, ArgIndex, JunctionOfConnectionType.Arg, ConnectionArgSourceType.GetPreviousNodeData, @@ -440,8 +461,15 @@ namespace Serein.NodeFlow.Model.Operation }); } - ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid = FromNode.Guid; // 设置 + ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid = FromNode.Guid; ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceType = ConnectionArgSourceType; + FromNode.NeedResultNodes[type].Add(ToNode); + + if (ToNode.ControlType == NodeControlType.Script) + { + // 脚本节点入参确定/改变来源时,更改对应的入参数据类型 + ToNode.MethodDetails.ParameterDetailss[ArgIndex].DataType = FromNode.MethodDetails.ReturnType; + } await TriggerEvent(() => { @@ -469,6 +497,7 @@ namespace Serein.NodeFlow.Model.Operation /// private async Task RemoveArgConnection() { + if (ToNode.MethodDetails.ParameterDetailss is null) return false; var type = ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceType; FromNode.NeedResultNodes[type].Remove(ToNode); ToNode.MethodDetails.ParameterDetailss[ArgIndex].ArgDataSourceNodeGuid = string.Empty; diff --git a/Serein.Script/Node/AssignmentNode.cs b/Serein.Script/Node/AssignmentNode.cs index b63c353..04d43e8 100644 --- a/Serein.Script/Node/AssignmentNode.cs +++ b/Serein.Script/Node/AssignmentNode.cs @@ -22,7 +22,7 @@ namespace Serein.Script.Node /// public ASTNode Value { get; } - public AssignmentNode(ASTNode targetObject, ASTNode value) => (Target, Value) = (targetObject, value); + public AssignmentNode(ASTNode target, ASTNode value) => (Target, Value) = (target, value); } diff --git a/Serein.Script/Node/ClassTypeDefinitionNode.cs b/Serein.Script/Node/ClassTypeDefinitionNode.cs index 878e48f..543ec07 100644 --- a/Serein.Script/Node/ClassTypeDefinitionNode.cs +++ b/Serein.Script/Node/ClassTypeDefinitionNode.cs @@ -22,8 +22,28 @@ namespace Serein.Script.Node /// /// 字段名称及字段类型 /// + [Obsolete("此属性已经过时,将会改为Dictionary", false)] public Dictionary Fields { get; } + + /// + /// 字段名称及字段类型(Kvp[fididName:fidleTypeName]) + /// + public Dictionary FieldInfos { get; } + public ClassTypeDefinitionNode(Dictionary fields, string className) + { + this.FieldInfos = fields; + this.ClassName = 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; diff --git a/Serein.Script/Node/CollectionIndexNode.cs b/Serein.Script/Node/CollectionIndexNode.cs index 4e088c0..ba6b100 100644 --- a/Serein.Script/Node/CollectionIndexNode.cs +++ b/Serein.Script/Node/CollectionIndexNode.cs @@ -20,10 +20,33 @@ namespace Serein.Script.Node /// 索引来源 /// public ASTNode Index { get; } - public CollectionIndexNode(ASTNode TargetValue,ASTNode indexValue) + + public CollectionIndexNode(ASTNode Collection, ASTNode indexValue) { - this.Collection = TargetValue; + this.Collection = Collection; this.Index = indexValue; } } + + /// + /// 集合赋值节点 + /// + public class CollectionAssignmentNode : ASTNode + { + /// + /// 集合来源 + /// + public CollectionIndexNode Collection { get; } + + /// + /// 索引来源 + /// + public ASTNode Value { get; } + + public CollectionAssignmentNode(CollectionIndexNode collection, ASTNode value) + { + this.Collection = collection; + this.Value = value; + } + } } diff --git a/Serein.Script/Node/ObjectMemberExpressionNode.cs b/Serein.Script/Node/ExpressionNode.cs similarity index 67% rename from Serein.Script/Node/ObjectMemberExpressionNode.cs rename to Serein.Script/Node/ExpressionNode.cs index f5033d9..37c33de 100644 --- a/Serein.Script/Node/ObjectMemberExpressionNode.cs +++ b/Serein.Script/Node/ExpressionNode.cs @@ -1,13 +1,13 @@ namespace Serein.Script.Node { - public class ObjectMemberExpressionNode : ASTNode + public class ExpressionNode : ASTNode { /// /// 对象成员(嵌套获取) /// public ASTNode Value { get; } - public ObjectMemberExpressionNode(ASTNode value) + public ExpressionNode(ASTNode value) { this.Value = value; } diff --git a/Serein.Script/Node/IfNode.cs b/Serein.Script/Node/FlowControl/IfNode.cs similarity index 95% rename from Serein.Script/Node/IfNode.cs rename to Serein.Script/Node/FlowControl/IfNode.cs index b3b9308..8e0c05e 100644 --- a/Serein.Script/Node/IfNode.cs +++ b/Serein.Script/Node/FlowControl/IfNode.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Serein.Script.Node +namespace Serein.Script.Node.FlowControl { /// /// 条件节点 diff --git a/Serein.Script/Node/ProgramNode.cs b/Serein.Script/Node/FlowControl/ProgramNode.cs similarity index 92% rename from Serein.Script/Node/ProgramNode.cs rename to Serein.Script/Node/FlowControl/ProgramNode.cs index f56fd2d..d13d642 100644 --- a/Serein.Script/Node/ProgramNode.cs +++ b/Serein.Script/Node/FlowControl/ProgramNode.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Serein.Script.Node +namespace Serein.Script.Node.FlowControl { /// /// 程序入口 diff --git a/Serein.Script/Node/ReturnNode.cs b/Serein.Script/Node/FlowControl/ReturnNode.cs similarity index 92% rename from Serein.Script/Node/ReturnNode.cs rename to Serein.Script/Node/FlowControl/ReturnNode.cs index 2f49c5a..5031af4 100644 --- a/Serein.Script/Node/ReturnNode.cs +++ b/Serein.Script/Node/FlowControl/ReturnNode.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Serein.Script.Node +namespace Serein.Script.Node.FlowControl { /// /// 返回值 diff --git a/Serein.Script/Node/WhileNode.cs b/Serein.Script/Node/FlowControl/WhileNode.cs similarity index 93% rename from Serein.Script/Node/WhileNode.cs rename to Serein.Script/Node/FlowControl/WhileNode.cs index 18eb4f2..4bf83d5 100644 --- a/Serein.Script/Node/WhileNode.cs +++ b/Serein.Script/Node/FlowControl/WhileNode.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Serein.Script.Node +namespace Serein.Script.Node.FlowControl { /// /// 循环条件节点 diff --git a/Serein.Script/Node/BooleanNode.cs b/Serein.Script/Node/ValueNode/BooleanNode.cs similarity index 100% rename from Serein.Script/Node/BooleanNode.cs rename to Serein.Script/Node/ValueNode/BooleanNode.cs diff --git a/Serein.Script/Node/CharNode.cs b/Serein.Script/Node/ValueNode/CharNode.cs similarity index 100% rename from Serein.Script/Node/CharNode.cs rename to Serein.Script/Node/ValueNode/CharNode.cs diff --git a/Serein.Script/Node/NullNode.cs b/Serein.Script/Node/ValueNode/NullNode.cs similarity index 100% rename from Serein.Script/Node/NullNode.cs rename to Serein.Script/Node/ValueNode/NullNode.cs diff --git a/Serein.Script/Node/NumberIntNode.cs b/Serein.Script/Node/ValueNode/NumberNode.cs similarity index 100% rename from Serein.Script/Node/NumberIntNode.cs rename to Serein.Script/Node/ValueNode/NumberNode.cs diff --git a/Serein.Script/Node/StringNode.cs b/Serein.Script/Node/ValueNode/StringNode.cs similarity index 100% rename from Serein.Script/Node/StringNode.cs rename to Serein.Script/Node/ValueNode/StringNode.cs diff --git a/Serein.Script/SereinScriptInterpreter.cs b/Serein.Script/SereinScriptInterpreter.cs index a9c2f45..347ef53 100644 --- a/Serein.Script/SereinScriptInterpreter.cs +++ b/Serein.Script/SereinScriptInterpreter.cs @@ -2,10 +2,12 @@ using Serein.Library; using Serein.Library.Utils; using Serein.Script.Node; +using Serein.Script.Node.FlowControl; using System.ComponentModel.Design; using System.Reflection; using System.Reflection.Metadata.Ecma335; using System.Runtime.CompilerServices; +using System.Threading.Tasks; using System.Xml.Linq; namespace Serein.Script @@ -358,7 +360,10 @@ namespace Serein.Script case AssignmentNode assignment: // 出现在 = 右侧的表达式 await ExecutionAssignmentNodeAsync(context, assignment); break; - case ObjectMemberExpressionNode objectMemberExpressionNode: + case CollectionAssignmentNode collectionAssignmentNode: + await SetCollectionValue(context,collectionAssignmentNode); + break; + case ExpressionNode objectMemberExpressionNode: break; case MemberAssignmentNode memberAssignmentNode: // 设置对象属性 await SetMemberValue(context, memberAssignmentNode); @@ -455,8 +460,8 @@ namespace Serein.Script return await GetCollectionValue(context, collectionIndexNode); case ReturnNode returnNode: // 返回内容 return await EvaluateAsync(context, returnNode.Value); // 直接返回响应的内容 - case ObjectMemberExpressionNode objectMemberExpressionNode: // 对象链式表达式 - return await EvaluateAsync(context, objectMemberExpressionNode.Value); + case ExpressionNode expressionNode: // 表达式 + return await EvaluateAsync(context, expressionNode.Value); default: throw new SereinSciptException(node, $"解释器 EvaluateAsync() 未实现{node}节点行为"); } @@ -666,6 +671,79 @@ namespace Serein.Script 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 处理键值对 + if (targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Dictionary<,>)) + { + // 目标是键值对 + 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]); + } + } + #endregion + #region 处理集合对象 + else + { + if (indexValue is int index) + { + // 获取数组或集合对象 + // 访问数组或集合中的指定索引 + if (collectionValue is Array array) + { + if (index < 0 || index >= array.Length) + { + throw new ArgumentException($"解析{collectionValue}节点时,数组下标越界。"); + } + var valueValue = await EvaluateAsync(context, collectionAssignmentNode.Value); + array.SetValue(valueValue, index); + return; + } + else if (collectionValue is IList list) + { + if (index < 0 || index >= list.Count) + { + throw new ArgumentException($"解析{collectionValue}节点时,数组下标越界。"); + } + var valueValue = await EvaluateAsync(context, collectionAssignmentNode.Value); + list[index] = valueValue; + return; + } + else + { + throw new ArgumentException($"解析{collectionValue}节点时,左值并非有效集合。"); + } + } + } + #endregion + + throw new ArgumentException($"解析{collectionValue}节点时,左值并非有效集合。"); + + } /// /// 缓存method委托 diff --git a/Serein.Script/SereinScriptLexer.cs b/Serein.Script/SereinScriptLexer.cs index b7f3260..153bb04 100644 --- a/Serein.Script/SereinScriptLexer.cs +++ b/Serein.Script/SereinScriptLexer.cs @@ -174,6 +174,15 @@ namespace Serein.Script return nextToken; // 返回下一个 token } + /// + /// 重置Lexer + /// + public void Reset() + { + this._row = 0; + this._index = 0; + } + /// /// 根据 token 重置Lexer /// @@ -184,6 +193,7 @@ namespace Serein.Script this._index = token.StartIndex; } + internal Token NextToken() { diff --git a/Serein.Script/SereinScriptParser.cs b/Serein.Script/SereinScriptParser.cs index ccc61a7..1a98a4b 100644 --- a/Serein.Script/SereinScriptParser.cs +++ b/Serein.Script/SereinScriptParser.cs @@ -2,6 +2,7 @@ using Serein.Library; using Serein.Library.Utils; using Serein.Script.Node; +using Serein.Script.Node.FlowControl; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; @@ -21,10 +22,9 @@ namespace Serein.Script private Token _currentToken; - public SereinScriptParser(string script) + public SereinScriptParser() { - _lexer = new SereinScriptLexer(script); // 语法分析 - _currentToken = _lexer.NextToken(); + } @@ -32,14 +32,13 @@ namespace Serein.Script /// 解析脚本并返回 AST(抽象语法树)根节点。 /// /// - public ProgramNode Parse() + public ProgramNode Parse(string script) { - + _lexer = new SereinScriptLexer(script); // 语法分析 + _currentToken = _lexer.NextToken(); return Program(); } - - private List Statements { get; } = new List(); /// @@ -52,7 +51,8 @@ namespace Serein.Script while (_currentToken.Type != TokenType.EOF) { - var astNode = Statement(); // 解析单个语句 + //var astNode = Statement(); // 解析单个语句 + var astNode = Statement2(); // 解析单个语句 if (astNode == null) { continue; @@ -74,6 +74,935 @@ namespace Serein.Script }*/ } + private ASTNode Statement2() + { + + //_currentToken = _lexer.NextToken(); // 获取新的Token + if (_currentToken.Type == TokenType.Identifier) + { + /* 赋值语句与一般语句的表达形式 + 1. 赋值语句: + 目标对象 表达式获取 + Target() | = | Expression() | + | = | variable; | (变量) + | = | value; | 显式设置的字面量。 + | = | obj.Value...; | obj为之前的上下文中出现过的变量,调用表达式包含对象成员数组、方法 + | = | array[...]; | array为之前的上下文中出现过的变量。 + | = | array[...].Value...; | array为之前的上下文中出现过的变量。调用表达式包含对象成员数组、方法 + | = | new Class(...); | 实例化类型,包含构造函数 + + 补充:Target() 可能的成员 + 1. variable + 2. obj.Value... + 3. array[index] + 4. array[index].Value... + + 2. 一般语句(方法调用): + 1. localFunc(...); + 2. obj....Func(...); + 3. array[]....Func(...); + */ + + #region 分析是赋值语句还是一般语句。赋值语句中间存在 = 操作符,一般语句不存在。 + var backupToken = _currentToken; // 保存当前token + var peekCount = 0; // peek次数 + var isAssignment = false; // 指示操作类型,true代表赋值语句,false代表一般语句 + while (true) + { + // 分析阶段,不移动token + var peekToken = _lexer.PeekToken(peekCount++); // 预览下一个节点 + if (peekToken.Type == TokenType.Semicolon) break; // 遇到分号,结束词法分析 + if (JudgmentOperator(peekToken, "=")) + { + isAssignment = true; + break; + } + //if (peekToken.StartIndex >= _lexer.CodeLength) throw new Exception(); + } + #endregion + #region 生成 ASTNode + if (isAssignment) + { + // 以赋值语句的形式进行处理 + var assignmentNode = ParseAssignmentNode(); + NextToken();// 消耗 ";" + return assignmentNode; + } + else + { + // 以一般语句的形式进行处理,可当作表达式进行解析 + var targetNode = ParserExpression(); // 解析表达式 + NextToken();// 消耗 ";" + return targetNode; + } + #endregion + + } + else if (JudgmentKeyword("class")) // 定义对象 + { + var classDefinitionNode = ParseClassDefinitionNode(); + return classDefinitionNode; + } + else if (JudgmentKeyword("return")) // 返回语句 + { + var returnNode = ParseReturnNode(); + return returnNode; + } + else if (_currentToken.Type == TokenType.Keyword) // 语句块 + { + /* + 可能的关键字 + 1. if()...else... + 2. while(){...} + */ + return null; + } + + if(_currentToken.Type == TokenType.Semicolon) + { + NextToken(); // 消耗 ";" + return null; + } + throw new Exception("解析异常"); + /*else + { + // 为避免解析异常,除了 Statement() 方法以外,其它地方不需要对 TokenType.Semicolon 进行处理 + throw new Exception("解析异常, Statement() 方法以外的地方处理了 TokenType.Semicolon "); + }*/ + } + + /// + /// 解析赋值语句 + /// + /// + public ASTNode ParseAssignmentNode() + { + /* + 赋值语句: + 目标对象 表达式获取 + Target() | = | Expression() | + | = | variable; | (变量) + | = | value; | 显式设置的字面量。 + | = | obj.Value...; | obj为之前的上下文中出现过的变量,调用表达式包含对象成员数组、方法 + | = | array[...]; | array为之前的上下文中出现过的变量。 + | = | array[...].Value...; | array为之前的上下文中出现过的变量。调用表达式包含对象成员数组、方法 + | = | new Class(...); | 实例化类型,包含构造函数 + + 补充:Target() 可能的成员 + 1. variable + 2. obj.Value... + 3. array[index] + 4. array[index].Value... + + 循环获取token判断 + 如果是 "." ,代表需要从对象中获取成员(属性、方法调用、数组) + 如果是 "(" ,代表调用挂载的本地方法 + 如果是 "[" ,代表需要获取数组索引 + 如果是 "=" ,代表是变量赋值,退出循环 + */ + /* + 1. 获取成员 => PeekToken.Type = TokenType.Dot + 2. 获取集合 => PeekToken.Type = TokenType.SquareBracketsLeft + 3. 调用成员方法 => PeekToken.Type = TokenType.ParenthesisLeft + */ + //if (JudgmentOperator(_currentToken, "=")) break; // 退出 + //var tempPeekToken = _lexer.PeekToken(); + var backupToken = _currentToken; + var targetNode = new IdentifierNode(_currentToken.Value).SetTokenInfo(_currentToken); // 生成 Tagget 标记节点 + NextToken(); // 消耗当前标识符的定义 + List nodes = [targetNode]; + ASTNode? source = null; + if (!JudgmentOperator(_currentToken, "=")) + { + var peekToken2 = _lexer.PeekToken(); // 消耗 第一个标识符 + if (peekToken2.Type == TokenType.ParenthesisLeft) + { + // 解析调用挂载方法 + // ... = variable()()(); + // 暂时不支持柯里化调用... = variable()()(); + var functionCallNode = ParseFunctionCallNode(); + if (_currentToken.Type == TokenType.Semicolon) + { + return functionCallNode; + } + targetNode = functionCallNode; + } + else if (peekToken2.Type == TokenType.SquareBracketsLeft) + { + // 解析集合获取 + var collectionIndexNode = ParseCollectionIndexNode(targetNode); + if (_currentToken.Type == TokenType.Semicolon) + { + return collectionIndexNode; + } + targetNode = collectionIndexNode; + } + + // 开始解析 + while (true) + { + if (JudgmentOperator(_currentToken, "=")) break; // 退出 + var peekToken = _currentToken; // _lexer.PeekToken(); // 获取下一个token开始判断 + source = nodes[^1]; // 重定向节点 + if (peekToken.Type == TokenType.Dot) // 从对象获取 + { + /* + 1. 获取成员 => PeekToken.Type = TokenType.Dot + 2. 获取集合 => PeekToken.Type = TokenType.SquareBracketsLeft + 3. 调用成员方法 => PeekToken.Type = TokenType.ParenthesisLeft + */ + NextToken(); // 消耗 "." 并获取下一个成员。 + var peekToken3 = _lexer.PeekToken(); + if (JudgmentOperator(peekToken3, "=")) + { + var tempMemberAccessNode = ParseMemberAccessNode(source); // 获取对象中的成员 source.Value... + nodes.Add(tempMemberAccessNode); + break; + } + ASTNode tempNode = peekToken3.Type switch + { + TokenType.Dot => ParseMemberAccessNode(source), // 获取对象中的成员 source.Value... + TokenType.Semicolon => ParseMemberAccessNode(source), // 获取对象中的成员 source.Value... + TokenType.ParenthesisRight => ParseMemberAccessNode(source), // 获取对象中的成员 source.Value... + TokenType.SquareBracketsLeft => ParseCollectionIndexNode(source), // 获取集合中的元素 source[index].... + TokenType.ParenthesisLeft => ParseMemberFunctionCallNode(source), // 获取需要调用的方法 source(arg1,arg2...)... + _ => throw new Exception($"无法从对象获取成员,当前Token类型为 {peekToken.Type}。") + }; + nodes.Add(tempNode); + continue; // 结束当前轮次的token判断 + + } + else if (peekToken.Type == TokenType.ParenthesisLeft) // 调用对象方法 + { + var memberFunctionCallNode = ParseMemberFunctionCallNode(source); + nodes.Add(memberFunctionCallNode); + continue; // 结束当前轮次的token判断 + + } + else if (peekToken.Type == TokenType.SquareBracketsLeft) // 集合获取 + { + var collectionIndexNode = ParseCollectionIndexNode(source); + nodes.Add(collectionIndexNode); + continue; // 结束当前轮次的token判断 + } + /*else if (peekToken.Type == TokenType.Semicolon) + { + break; + } + else + { + if (peekToken.Type == TokenType.ParenthesisRight // 可能解析完了方法参数 + || peekToken.Type == TokenType.Comma // 可能解析完了方法参数 + || peekToken.Type == TokenType.ParenthesisRight) // 可能解析完了下标索引 + { + return source; + } + // 应该是异常,如果是其它符号,说明词法解析不符合预期 + throw new Exception($"在 Expression().Factor() 遇到意外的 TokenType ,{_currentToken.Type} {_currentToken.Value} "); + }*/ + } + + } + targetNode = nodes[^1]; + if (targetNode is FunctionCallNode or MemberFunctionCallNode) + { + throw new Exception($"赋值语句左值部分不允许为方法调用,{targetNode.Code}"); + } + else + { + // 反转赋值。 + NextToken(); // 消耗 "=" 并获取赋值语句的右值表达式。 + ASTNode valueNode = ParserExpression(); + if (targetNode is MemberAccessNode memberAccessNode) + { + MemberAssignmentNode memberAssignmentNode = new MemberAssignmentNode(memberAccessNode.Object, memberAccessNode.MemberName, valueNode); + return memberAssignmentNode; + } + else if (targetNode is CollectionIndexNode collectionIndeNode) + { + CollectionAssignmentNode collectionAssignmentNode = new CollectionAssignmentNode(collectionIndeNode, valueNode); + return collectionAssignmentNode; + } + else + { + // 获取赋值节点 + AssignmentNode assignmentNode = new AssignmentNode(target: targetNode, value: valueNode); + return assignmentNode; + } + + } + + } + + /// + /// (不处理分号)解析获取“集合获取”AST节点 + /// + /// + /// + public MemberAccessNode ParseMemberAccessNode(ASTNode sourceNode) + { + string memberName = _currentToken.Value; // 成员名称 + var memberAccessNode = new MemberAccessNode(sourceNode, memberName); + NextToken(); // 消耗成员名称 + memberAccessNode.SetTokenInfo(_currentToken); + return memberAccessNode; + } + + /// + /// (不处理分号)解析获取“集合获取”AST节点 + /// + /// + /// + public CollectionIndexNode ParseCollectionIndexNode(ASTNode sourceNode) + { + var collectionToken = _currentToken; + string collectionName = _currentToken.Value; // 集合名称 + NextToken(TokenType.SquareBracketsLeft); // 消耗集合名称 + NextToken(); // 消耗 "[" 集合标识符的左中括号 + ASTNode indexNode = ParserExpression(); // 解析获取索引Node + NextToken(); // 消耗 "]" 集合标识符的右中括号 + + if(sourceNode is IdentifierNode) + { + var collectionIndexNode = new CollectionIndexNode(sourceNode, indexNode); + collectionIndexNode.SetTokenInfo(collectionToken); // 表示获取集合第几个索引 + return collectionIndexNode; + } + else + { + + var memberAccessNode = new MemberAccessNode(sourceNode, collectionName).SetTokenInfo(_currentToken); // 表示集合从上一轮获取到的成员获取 + var collectionIndexNode = new CollectionIndexNode(memberAccessNode, indexNode); + collectionIndexNode.SetTokenInfo(collectionToken); // 表示获取集合第几个索引 + return collectionIndexNode; + } + + } + + /// + /// (不处理分号)解析获取“对象方法调用”AST节点 + /// + /// + /// + public MemberFunctionCallNode ParseMemberFunctionCallNode(ASTNode sourceNode) + { + string methodName = _currentToken.Value; // 方法名称 + NextToken(TokenType.ParenthesisLeft); // 消耗方法名称 + List argNodes = []; // 方法参数Node + NextToken(); // 消耗 "(" + while (_currentToken.Type != TokenType.ParenthesisRight) // 遇到 ")" 表示参数获取完毕 + { + ASTNode node = ParserArgNode(); // 解析方法调用参数 + argNodes.Add(node); + if (_currentToken.Type == TokenType.Comma) + { + NextToken(); // 消耗参数分隔符 "," + } + } + NextToken(); // 消耗 ")" 表示参数获取完毕 + var memberFunctionCallNode = new MemberFunctionCallNode(sourceNode, methodName, argNodes); + memberFunctionCallNode.SetTokenInfo(_currentToken); + return memberFunctionCallNode; // 结束当前轮次的token判断 + } + + /// + /// (不处理分号)解析获取“调用挂载的方法”AST节点 + /// + /// + public FunctionCallNode ParseFunctionCallNode() + { + string functionName = _currentToken.Value; // 方法名称 + NextToken(TokenType.ParenthesisLeft); // 消耗方法名称 + List argNodes = []; // 方法参数Node、 + NextToken(); // 消耗 "(" + while (_currentToken.Type != TokenType.ParenthesisRight) // 遇到 ")" 表示参数获取完毕 + { + ASTNode node = ParserArgNode(); // 解析挂载方法的入参 + argNodes.Add(node); + if (_currentToken.Type == TokenType.Comma) + { + NextToken(); // 消耗参数分隔符 "," + } + } + NextToken(); // 消耗 ")" + var functionCallNode = new FunctionCallNode(functionName, argNodes); + functionCallNode.SetTokenInfo(_currentToken); + return functionCallNode; + } + + /// + /// (不处理分号,逗号,右括号)用于解析(...)中的参数部分。终止条件是 "," 参数分隔符 和 ")" 方法入参终止符 + /// + /// + public ASTNode ParserArgNode() + { + ASTNode node = ParserExpression(); // 解析参数 + // ParserExpression 会完全解析当前表达式,自动移动到下一个Token,所以需要在这里判断是否符合期望的TokenType + if(_currentToken.Type == TokenType.Comma || _currentToken.Type == TokenType.ParenthesisRight) + { + return node; + } + throw new Exception($"解析参数节点后,当前Token类型不符合预期,当前类型为 {_currentToken.Type}。"); + } + + /// + /// (没有分号)解析类定义 + /// + /// + /// + private ASTNode ParseClassDefinitionNode() + { + /* + class [ClassName] { + FieldType FieldName1; + FieldType FieldName2; + FieldType FieldName3; + FieldType FieldName4; + } + */ + var coreStartRangeIndex = _lexer.GetIndex(); // 从“class”开始锚定代码范围 + if (!JudgmentKeyword("class")) throw new Exception($"解析类型定义节点时,当前Token不为关键字“class”。"); + NextToken(TokenType.Identifier); // 消耗“class”关键字,获取类名 + string className = _currentToken.Value; // 类型名称 + NextToken(TokenType.BraceLeft); // 消耗类型名称,并判断是否为 "{" + NextToken(); + var classFields = new Dictionary(); // 记录类型中定义的字段 + while (_currentToken.Type != TokenType.BraceRight) // 遇到 "}" 时表示类型解析完毕 + { + // 获取字段的类型、名称,类型允许包含逗号(使用C#中的类型) + /* + class User { + System.Int32 Age; // 等效于 int Age; + } + 字段解析时的预期顺序: + 1 2 3 4 5 6 + [id -> dot -> id -> dot -> id] -> id -> Semicolon + [ 字段定义 ] 字段名称 解析完成 + */ + string fieldTypeName = _currentToken.Value; + string fieldName; + while (true) + { + var peekToken = _lexer.PeekToken(); + if (peekToken.Type == TokenType.Dot) + { + NextToken(TokenType.Identifier); + fieldTypeName = $"{fieldTypeName}.{_currentToken.Value}"; // 向后扩充 + NextToken(); + continue; + } + else if (peekToken.Type == TokenType.Identifier) + { + // 尝试解析变量名称 + fieldName = peekToken.Value; // 字段名称 + NextToken(); // 消耗类型定义的最后一个Token + NextToken(TokenType.Semicolon); // 消耗字段名称,如果下一个Token如果不为分号,说明词法异常 + break; + } + } + var fieldType = DynamicObjectHelper.GetCacheType(fieldTypeName); // 查询是否在其它脚本中创建过类型 + fieldType = fieldType ?? fieldTypeName.ToTypeOfString(); // 如果没有定义过类型,则从c#运行时尝试获取类型 + if(fieldType is null) + { + throw new Exception($"定义类型 {className} 时,解析成员 {fieldName} 失败,没有找到类型 {fieldTypeName}。"); + } + classFields.Add(fieldName, fieldType); + NextToken(); // 当前字段类型定义完毕,消耗";" + } + var classToken = _currentToken; + classToken.Code = _lexer.GetCoreContent(coreStartRangeIndex); // 收集类型定义的代码。 + NextToken(); // 当前类型定义完毕,消耗"}" + + // 词法分析时不应该获取类型,类型应该放在类型分支中进行追踪 + var type = DynamicObjectHelper.GetCacheType(className); + if(type is null) // 解析时创建类型,因为后续的类型定义中,某个字段可能使用该类型,而解析时需要获取到其类型 + { + DynamicObjectHelper.CreateTypeWithProperties(classFields, className); + } + + var classTypeDefinitionNode = new ClassTypeDefinitionNode(classFields, className); + + classTypeDefinitionNode.SetTokenInfo(classToken); + return classTypeDefinitionNode; + } + + /// + /// 解析 return 语句。 + /// + /// + public ReturnNode ParseReturnNode() + { + var returnToken = _currentToken; + if (JudgmentKeyword("return")) throw new Exception($"解析返回节点时,当前Token不为关键字“return”。"); + NextToken(); // 消耗关键字 + ReturnNode returnNode; + if (_currentToken.Type == TokenType.Semicolon) + { + returnNode = new ReturnNode(); // 空返回 + } + else + { + var resultValue = BooleanExpression(); // 解析值表达式 + returnNode = new ReturnNode(resultValue); // 带值返回 + } + returnNode.SetTokenInfo(returnToken); + if (_currentToken.Type == TokenType.Semicolon) + { + NextToken(); // 消耗 ";" ,语句完毕 + } + return returnNode; + } + + /// + /// (不处理分号)解析对象实例化行为 + /// + /// + /// + public ObjectInstantiationNode ParseObjectInstantiationNode() + { + + // 获取类型名称,类型允许包含逗号(使用C#中的类型) + /* + new [TypeName]([Exp1],[Exp2]); + 类型解析时的预期顺序: + 1 2 3 4 5 6 + new -> [id -> dot -> id -> dot -> id] -> ParenthesisLeft -> [CtroArg] -> ParenthesisRight -> Semicolon + [ 类型定义 ] 括号 "(" 构造入参 括号 ")" 分号,解析完成 + */ + var instantiationToken = _currentToken; + // 第一次进入循环时,会消耗 new 关键字 + NextToken(TokenType.Identifier); + string typeName = _currentToken.Value; // 类名 + List ctorArguments = []; // 构造入参 + while (true) + { + + var peekToken = _lexer.PeekToken(); + if (peekToken.Type == TokenType.Dot) + { + + typeName = $"{typeName}.{_currentToken.Value}"; // 向后扩充 + NextToken(); + continue; + } + else if (peekToken.Type == TokenType.ParenthesisLeft) + { + // 类名定义完成,解析构造方法入参。 + NextToken(); // 消耗 类型Token + NextToken(); // 消耗 "(" + while (_currentToken.Type != TokenType.ParenthesisRight) // 表示参数获取完毕 + { + ASTNode node = ParserArgNode(); // 解析构造方法的入参 + ctorArguments.Add(node); + if(_currentToken.Type == TokenType.Comma) + { + NextToken(); // 消耗参数分隔符 "," + } + } + NextToken(); // 消耗 ")" + break; + } + } + // NextToken(TokenType.Semicolon); // 消耗字段名称,如果下一个Token如果不为分号,说明词法异常 + ObjectInstantiationNode objectInstantiationNode = new ObjectInstantiationNode(typeName, ctorArguments); + objectInstantiationNode.SetTokenInfo(instantiationToken); + return objectInstantiationNode; + } + + #region 表达式解析:BooleanExpression -> ComparisonExpression -> Expression -> Term -> Factor + /// + /// 解析表达式 + /// + /// + private ASTNode ParserExpression() + { + // 处理表达式时,从布尔表达式开始。 + return BooleanExpression(); + } + #region 表达式处理 + + /// + /// 布尔表达式 + /// + /// + private ASTNode BooleanExpression() + { + ASTNode left = ComparisonExpression(); + + while (_currentToken.Type == TokenType.Operator && + (_currentToken.Value == "&&" || _currentToken.Value == "||")) + { + string op = _currentToken.Value; + _currentToken = _lexer.NextToken(); + ASTNode right = ComparisonExpression(); + left = new BinaryOperationNode(left, op, right).SetTokenInfo(_currentToken); + } + + return left; + } + + /// + /// 比较表达式(==, !=, <, <=, >, >=) + /// + /// + private ASTNode ComparisonExpression() + { + ASTNode left = Expression(); + + while (_currentToken.Type == TokenType.Operator && + (_currentToken.Value == "==" || _currentToken.Value == "!=" || + _currentToken.Value == "<" || _currentToken.Value == "<=" || + _currentToken.Value == ">" || _currentToken.Value == ">=")) + { + string op = _currentToken.Value; + _currentToken = _lexer.NextToken(); + ASTNode right = Expression(); + left = new BinaryOperationNode(left, op, right).SetTokenInfo(_currentToken); + } + + return left; + } + + /// + /// 加减 + /// + /// + private ASTNode Expression() + { + ASTNode left = Term(); + + while (_currentToken.Type == TokenType.Operator && + (_currentToken.Value == "+" || _currentToken.Value == "-")) + { + string op = _currentToken.Value; + _currentToken = _lexer.NextToken(); + ASTNode right = Term(); + left = new BinaryOperationNode(left, op, right).SetTokenInfo(_currentToken); + } + + return left; + } + + /// + /// 乘除 + /// + /// + private ASTNode Term() + { + ASTNode left = Factor(); + while (_currentToken.Type == TokenType.Operator && + (_currentToken.Value == "*" || _currentToken.Value == "/")) + { + string op = _currentToken.Value; + _currentToken = _lexer.NextToken(); + ASTNode right = Factor(); + left = new BinaryOperationNode(left, op, right).SetTokenInfo(_currentToken); + } + + return left; + } + #endregion + + /// + /// 解析因子(Factor),用于处理基本的字面量、标识符、括号表达式等。 + /// + /// + /// + private ASTNode Factor() + { + /* + + 表达式类型: + 1. 赋值语句中的右值 ... = [Exp];(左值不为表达式) + 2. 一般语句 [Exp]; + 3. 方法中参数 func([Exp1],[Exp2],[Exp3]...) 单个入参 + 3. 实例化类型 new Class(); + 表达式特征: + a. 在第 1 次分析中,当 _currentToken.Type 为 Identifier 时,下一个 Token 可能为: + 1. TokenType.ParenthesisLeft => 调用本地方法 + 2. TokenType.Dot => 当前 Toke 代表变量,需要获取对象成员 + 3. TokenType.ParenthesisLeft => 当前 Token 表示数组对象,索引为 PeekToken(2),根据索引获取成员 + 4. TokenType.Keyword("new") => 实例化类型 + 5. TokenType.Semicolon => 表达式结束 + b. 在第 N + 1 次分析中,当 _currentToken.Type 为 Identifier 时,下一个 Token 可能为: + 1. TokenType.ParenthesisLeft => 以上一次分析得到的 Node 为 Source Object,调用其的方法。 + 2. TokenType.Dot => 以上一次分析得到的 Node 为 Source Object,需要获取对象成员 + 3. TokenType.ParenthesisLeft => 以上一次分析得到的 Node 为 Source Object,获取 _currentToken.Value 对应的数组成员,索引为 PeekToken(2),根据索引获取成员 + 4. TokenType.Keyword("new") => 实例化类型 + 5. TokenType.Semicolon => 表达式结束 + c. 当 _currentToken.Type 为 ParenthesisLeft 时 : + 存在嵌套表达式,再次调用 ParserExpression() 方法。 + + */ + + // 标识符节点 + var factorToken = _currentToken; // 记录一下进入 Factor() 的 Token + if (_currentToken.Type == TokenType.Identifier) + { + /* + 表达式获取 Expression() + variable; | 变量 √ + value; | 显式设置的字面量。 √ + obj.Value...; | obj为之前的上下文中出现过的变量,调用表达式包含对象成员数组、方法 + array[...]; | array为之前的上下文中出现过的变量。 + array[...].Value...; | array为之前的上下文中出现过的变量。调用表达式包含对象成员数组、方法 + new Class(...); | 实例化类型,包含构造函数 √ + */ + var backupToken = _currentToken; + //var tempPeekToken = _lexer.PeekToken(); + var targetNode = new IdentifierNode(_currentToken.Value).SetTokenInfo(_currentToken); // 获取变量 + var peekToken2 = _lexer.PeekToken(); // 消耗 第一个标识符 + + if (peekToken2.Type == TokenType.Semicolon + || peekToken2.Type == TokenType.ParenthesisRight + || peekToken2.Type == TokenType.SquareBracketsRight + || peekToken2.Type == TokenType.Comma + || peekToken2.Type == TokenType.Operator + ) + { + NextToken(); // 消耗标识符 + return targetNode; + } + if (peekToken2.Type == TokenType.ParenthesisLeft) + { + // 解析调用挂载方法 + // ... = variable()()(); + // 暂时不支持柯里化调用... = variable()()(); + var functionCallNode = ParseFunctionCallNode(); + if(_currentToken.Type == TokenType.Semicolon) + { + return functionCallNode; + } + targetNode = functionCallNode; + } + else if (peekToken2.Type == TokenType.SquareBracketsLeft) + { + // 解析集合获取 + var collectionIndexNode = ParseCollectionIndexNode(targetNode); + if (_currentToken.Type == TokenType.Semicolon) + { + return collectionIndexNode; + } + targetNode = collectionIndexNode; + }else if (peekToken2.Type == TokenType.Dot) + { + NextToken(); // 消耗标识符 + } + + // 开始解析 + List nodes = [targetNode]; + ASTNode? source; + while (true) + { + var peekToken = _currentToken; // _lexer.PeekToken(); // 获取下一个token开始判断 + source = nodes[^1]; // 重定向节点 + if (peekToken.Type == TokenType.Dot) // 从对象获取 + { + /* + 1. 获取成员 => PeekToken.Type = TokenType.Dot + 2. 获取集合 => PeekToken.Type = TokenType.SquareBracketsLeft + 3. 调用成员方法 => PeekToken.Type = TokenType.ParenthesisLeft + */ + NextToken(); // 消耗 "." 并获取下一个成员。 + var peekToken3 = _lexer.PeekToken(); + ASTNode tempNode = peekToken3.Type switch + { + TokenType.Dot => ParseMemberAccessNode(source), // 获取对象中的成员 source.Value... + TokenType.Semicolon => ParseMemberAccessNode(source), // 获取对象中的成员 source.Value... + TokenType.ParenthesisRight => ParseMemberAccessNode(source), // 获取对象中的成员 source.Value... + TokenType.SquareBracketsLeft => ParseCollectionIndexNode(source), // 获取集合中的元素 source[index].... + TokenType.ParenthesisLeft => ParseMemberFunctionCallNode(source), // 获取需要调用的方法 source(arg1,arg2...)... + _ => throw new Exception($"无法从对象获取成员,当前Token类型为 {peekToken.Type}。") + }; + nodes.Add(tempNode); + continue; // 结束当前轮次的token判断 + + } + else if (peekToken.Type == TokenType.ParenthesisLeft) // 调用对象方法 + { + var memberFunctionCallNode = ParseMemberFunctionCallNode(source); + nodes.Add(memberFunctionCallNode); + continue; // 结束当前轮次的token判断 + + } + else if (peekToken.Type == TokenType.SquareBracketsLeft) // 集合获取 + { + var collectionIndexNode = ParseCollectionIndexNode(source); + nodes.Add(collectionIndexNode); + continue; // 结束当前轮次的token判断 + } + else if (peekToken.Type == TokenType.Semicolon) + { + break; + } + else + { + if(peekToken.Type == TokenType.ParenthesisRight // 可能解析完了方法参数 + || peekToken.Type == TokenType.Comma // 可能解析完了方法参数 + || peekToken.Type == TokenType.ParenthesisRight) // 可能解析完了下标索引 + { + return source; + } + // 应该是异常,如果是其它符号,说明词法解析不符合预期 + throw new Exception($"在 Expression().Factor() 遇到意外的 Token: [{_currentToken.Type}]\"{_currentToken.Value}\" "); + + } + } + return source; + + } + else if (_currentToken.Type == TokenType.ParenthesisLeft) // 嵌套表达式 + { + NextToken(); // 消耗 "(" + _currentToken = _lexer.NextToken(); // 消耗 "(" + var expNode = BooleanExpression(); + if (_currentToken.Type != TokenType.ParenthesisRight) + throw new Exception($"解析嵌套表达式时遇到非预期的符号 \"{_currentToken.Type}\",预期符号为\")\"。"); + NextToken(); // 消耗 ")" + return expNode; + } + else if(_currentToken.Type == TokenType.Keyword && _currentToken.Value == "new") // 创建对象 + { + return ParseObjectInstantiationNode(); + } + + #region 字面量因子 + else if (_currentToken.Type == TokenType.Null) + { + NextToken(); // 消耗 null + return new NullNode().SetTokenInfo(factorToken); + } + else if (_currentToken.Type == TokenType.Boolean) + { + var value = bool.Parse(_currentToken.Value); + NextToken(); // 消耗布尔量 + return new BooleanNode(value).SetTokenInfo(factorToken); + } + else if (_currentToken.Type == TokenType.String) + { + var value = _currentToken.Value; + NextToken(); // 消耗字符串 + var node = new StringNode(value).SetTokenInfo(factorToken); + return node; + } + else if (_currentToken.Type == TokenType.Char) + { + var value = _currentToken.Value; + NextToken(); ; // 消耗Char + return new CharNode(value).SetTokenInfo(factorToken); + } + else if (_currentToken.Type == TokenType.InterpolatedString) + { + // 暂未实现插值字符串 + // 可能是插值字符串; + // let context = $"a{A}b{B}c"; + // let context = "a" + A + "b" + B + c; + NextToken(); // 消耗字符串 + while (_currentToken.Type == TokenType.String) + { + } + } + else if (_currentToken.Type == TokenType.NumberInt) + { + var value = int.Parse(_currentToken.Value); + NextToken(); // 消耗 int 整型 + return new NumberIntNode(value).SetTokenInfo(factorToken); + } + else if (_currentToken.Type == TokenType.NumberLong) + { + var value = long.Parse(_currentToken.Value); + NextToken(); // 消耗 long 整型 + return new NumberLongNode(value).SetTokenInfo(factorToken); + } + else if (_currentToken.Type == TokenType.NumberFloat) + { + var value = float.Parse(_currentToken.Value); + NextToken(); // 消耗 float 浮点数 + return new NumberFloatNode(value).SetTokenInfo(factorToken); + } + else if (_currentToken.Type == TokenType.NumberDouble) + { + var value = float.Parse(_currentToken.Value); + NextToken(); // 消耗 double 浮点数 + return new NumberDoubleNode(value).SetTokenInfo(factorToken); + } + #endregion + + + throw new Exception($"在 Expression().Factor() 遇到意外的 TokenType ,{_currentToken.Type} {_currentToken.Value} "); + } + #endregion + + #region 辅助方法 + + private Token NextToken() + { + _currentToken = _lexer.NextToken(); + return _currentToken; + } + + private Token NextToken(TokenType expectationTokenType) + { + _currentToken = _lexer.NextToken(); + if(_currentToken.Type != expectationTokenType) + { + throw new Exception($"分析器获取下一个Token时,期望获取 {expectationTokenType} ,但实际获取 {_currentToken.Type}。" + + $"Value : {_currentToken.Value}" + + $"StartIndex : {_currentToken.StartIndex}" + + $"Length : {_currentToken.Length}" + + $""); + } + return _currentToken; + } + + /// + /// 判断当前Token操作符类型 + /// + /// + /// + private bool JudgmentTokenType(TokenType tokenType) + { + return _currentToken.Type == tokenType; + } + + /// + /// 判断Token操作符类型 + /// + /// + /// + private bool JudgmentOperator(Token peekToken, string @operator) + { + if (peekToken.Type != TokenType.Operator) + { + return false; + } + return peekToken.Value == @operator; + } + + /// + /// 判断当前Token关键字类型 + /// + /// + /// + private bool JudgmentKeyword(string keyword) + { + if (_currentToken.Type != TokenType.Keyword) + { + return false; + } + return _currentToken.Value == keyword; + } + + + + #endregion + + + + #region 废弃的解析方法 + /* + + /// /// 解析单个语句。 /// @@ -82,16 +1011,19 @@ namespace Serein.Script private ASTNode Statement() { - // 处理其他语句(如表达式语句等) while (_currentToken.Type == TokenType.Semicolon) { _currentToken = _lexer.NextToken(); } - if(_currentToken.Type == TokenType.EOF) + if (_currentToken.Type == TokenType.EOF) { return null; } - + if (_currentToken.Type == TokenType.Identifier) + { + // 处理标识符,可能是函数调用、变量赋值或对象成员访问等行为 + return ParseIdentifier(); + } if (_currentToken.Type == TokenType.Keyword && _currentToken.Value == "let") { @@ -129,24 +1061,19 @@ namespace Serein.Script // 处理 return 语句 return ParseReturn(); } - if (_currentToken.Type == TokenType.Identifier) - { - // 处理标识符,可能是函数调用、变量赋值或对象成员访问等行为 - return ParseIdentifier(); - } + if (_currentToken.Type == TokenType.Null) { // 处理 null 语句 return BooleanExpression(); - return Expression(); } - /*if (_currentToken.Type == TokenType.Semicolon) + *//**//* + // 处理其他语句(如表达式语句等) + if (_currentToken.Type == TokenType.Semicolon) { - _currentToken = _lexer.NextToken(); return null; // 表示空语句 - }*/ - + } throw new Exception("Unexpected statement: " + _currentToken.Value.ToString()); @@ -160,54 +1087,23 @@ namespace Serein.Script /// private ASTNode ParseIdentifier() { - /* + *//* localFunc(); obj.Func(); obj.Value = ...; value = ...; - */ + *//* var backupToken = _currentToken; var tokenCount = 1; var int_type = 0; - while (true) - { - var tempToken = _lexer.PeekToken(tokenCount++); - if (tempToken.Type == TokenType.Operator && tempToken.Value == "=") - { - var tempToken2 = _lexer.PeekToken(tokenCount); - if (tempToken2.Type == TokenType.SquareBracketsRight) - { - int_type = 2; // 变量数组赋值 - break; - } - else // if (tempToken2.Type == TokenType.SquareBracketsRight) - { - int_type = 1; // 变量赋值 - break; - } - } - if (tempToken.Type == TokenType.Semicolon) - { - var tempToken2 = _lexer.PeekToken(tokenCount); - if(tempToken2.Type == TokenType.ParenthesisRight) - { - int_type = 3; // 方法调用 - break; - } - } - if(tempToken.Type == TokenType.ParenthesisLeft) // 本地函数调用 - { - int_type = 4; // 本地方法调用 - break; - } - - } - if(int_type == 1) // 赋值 MemberAssignmentNode + int_type = GetFlowType(_lexer, ref tokenCount); + if (int_type == 1) // 赋值 MemberAssignmentNode { + //_lexer.SetToken(backupToken); var objectName = _currentToken.Value; var objectNode = new IdentifierNode(objectName).SetTokenInfo(_currentToken); // 首先定义对象变量节点 var peekToken = _lexer.PeekToken(); - if(peekToken.Type == TokenType.Operator && peekToken.Value == "=") + if (peekToken.Type == TokenType.Operator && peekToken.Value == "=") { // 变量赋值 _currentToken = _lexer.NextToken(); // 消耗 变量名 @@ -217,103 +1113,155 @@ namespace Serein.Script var assignmentNode = new AssignmentNode(objectNode, valueNode).SetTokenInfo(_currentToken); return assignmentNode; } - else + + _currentToken = _lexer.NextToken(); // 消耗对象名称 + //_lexer.SetToken(backupToken); + + List nodes = new List(); // 表达对象成员路径的节点 + while (true) { - _currentToken = _lexer.NextToken(); // 消耗对象名称 - // 对象成员赋值 - List nodes = new List(); // 表达对象成员路径的节点 - while (true) + if (_currentToken.Type != TokenType.Dot) { - if (_currentToken.Type == TokenType.Dot) - { - _currentToken = _lexer.NextToken(); // 消耗 "." 获取下一个成员 - if (_currentToken.Type == TokenType.Identifier) - { - var temp2token = _lexer.PeekToken(); - var sourceNode = nodes.Count == 0 ? objectNode : nodes[^1]; - if (temp2token.Type == TokenType.ParenthesisLeft) - { - // 解析方法调用 obj.func() - ASTNode functionNode = ParseMemberFunctionCall(sourceNode).SetTokenInfo(_currentToken); - nodes.Add(functionNode); - } - else if (temp2token.Type == TokenType.SquareBracketsLeft) - { - // 成员数组 obj.dict[key] / obj.array[index] - if (_currentToken.Type == TokenType.Identifier) - { - var memberAccessNode = new MemberAccessNode(sourceNode, _currentToken.Value).SetTokenInfo(_currentToken); - sourceNode = memberAccessNode; - } - var coolectionNode = ParseCollectionIndex(sourceNode).SetTokenInfo(_currentToken); - nodes.Add(coolectionNode); - } - else if (temp2token.Type is TokenType.Dot /* or TokenType.ParenthesisRight*/) - { - // 成员获取 obj.value - var memberAccessNode = new MemberAccessNode(sourceNode, _currentToken.Value).SetTokenInfo(_currentToken); - nodes.Add(memberAccessNode); - } - else if (temp2token.Type == TokenType.Operator && temp2token.Value == "=") - { - // 左值结束, 成员获取 obj.value - /* var memberAccessNode = new MemberAccessNode(sourceNode, _currentToken.Value).SetTokenInfo(_currentToken); - nodes.Add(memberAccessNode);*/ - var memberName = _currentToken.Value; // 成员名称 - _currentToken = _lexer.NextToken(); // 消耗 成员 token - _currentToken = _lexer.NextToken(); // 消耗“=” 等号 - var rightNode = BooleanExpression(); // 判断token - MemberAssignmentNode assignmentNode = new MemberAssignmentNode(sourceNode, memberName, rightNode); - assignmentNode.SetTokenInfo(_currentToken); - - return assignmentNode; // 返回节点 - break; - } - //_lexer.SetToken(peekToken); // 重置lexer - } - } - else - { - _currentToken = _lexer.NextToken(); - } - /*if (_currentToken.Type == TokenType.Operator && _currentToken.Value == "=") - { - // 等号意味着左值语句结束 - break; - }*/ + _currentToken = _lexer.NextToken(); + continue; } - - /* var leftValueNodes = nodes; - List rightValueNode = new List(); // 表达对象成员路径的节点*/ + _currentToken = _lexer.NextToken(); // 消耗 "." 获取下一个成员 + if (_currentToken.Type != TokenType.Identifier) + { + continue; + //_lexer.SetToken(peekToken); // 重置lexer + } + var temp2token = _lexer.PeekToken(); + var sourceNode = nodes.Count == 0 ? objectNode : nodes[^1]; + if (temp2token.Type == TokenType.ParenthesisLeft) + { + // 解析方法调用 obj.func() + ASTNode functionNode = ParseMemberFunctionCall(sourceNode).SetTokenInfo(_currentToken); + nodes.Add(functionNode); + } + else if (temp2token.Type == TokenType.SquareBracketsLeft) + { + // 成员数组 obj.dict[key] / obj.array[index] + if (_currentToken.Type == TokenType.Identifier) + { + var memberAccessNode = new MemberAccessNode(sourceNode, _currentToken.Value).SetTokenInfo(_currentToken); + sourceNode = memberAccessNode; + } + var coolectionNode = ParseCollectionIndex(sourceNode).SetTokenInfo(_currentToken); + nodes.Add(coolectionNode); + } + else if (temp2token.Type is TokenType.Dot *//* or TokenType.ParenthesisRight*//*) + { + // 成员获取 obj.value + var memberAccessNode = new MemberAccessNode(sourceNode, _currentToken.Value).SetTokenInfo(_currentToken); + nodes.Add(memberAccessNode); + } + else if (temp2token.Type == TokenType.Operator && temp2token.Value == "=") + { + // 左值结束, 成员获取 obj.value + *//* var memberAccessNode = new MemberAccessNode(sourceNode, _currentToken.Value).SetTokenInfo(_currentToken); + nodes.Add(memberAccessNode);*//* + var memberName = _currentToken.Value; // 成员名称 + _currentToken = _lexer.NextToken(); // 消耗 成员 token + _currentToken = _lexer.NextToken(); // 消耗“=” 等号 + var rightNode = BooleanExpression(); // 判断token + MemberAssignmentNode assignmentNode = new MemberAssignmentNode(sourceNode, memberName, rightNode); + assignmentNode.SetTokenInfo(_currentToken); + return assignmentNode; // 返回节点 + } } - - - } - else if (int_type == 2) // 方法调用 + else if (int_type == 2) // 变量数组赋值 { + var objectName = _currentToken.Value; + var objectNode = new IdentifierNode(objectName).SetTokenInfo(_currentToken); // 首先定义对象变量节点 + _currentToken = _lexer.NextToken(); // 消耗 变量名称 + if (_currentToken.Type != TokenType.SquareBracketsLeft) + throw new Exception("数组需要 '[' 符号"); + _currentToken = _lexer.NextToken(); // 消耗 "[" + ASTNode indexValue = BooleanExpression(); // 获取表达数组下标的节点 + + _currentToken = _lexer.NextToken(); // 消耗 "]" + var collectionNode = new CollectionIndexNode(objectNode, indexValue); + collectionNode.SetTokenInfo(_currentToken); // 集合节点 + + if (!(_currentToken.Type == TokenType.Operator && _currentToken.Value == "=")) + throw new Exception("数组赋值需要 '=' 符号"); + _currentToken = _lexer.NextToken(); // 消耗 "=" + + var valueNode = BooleanExpression(); // 获取右值表达式 + + var assignmentNode = new CollectionAssignmentNode(collectionNode, valueNode).SetTokenInfo(_currentToken); // 集合节点; + return assignmentNode; + var tempToken1 = _lexer.PeekToken(1); + var tempToken2 = _lexer.PeekToken(2); + var tempToken3 = _lexer.PeekToken(3); + _currentToken = _lexer.NextToken(); + // object[1] = ""; var taretNode = ""; - } - else if (int_type == 3) // 方法调用 - { - var taretNode = ""; - } + } + *//* else if (int_type == 3) // 方法调用 + { + var taretNode = ""; + }*//* else if (int_type == 4) // 方法调用 { // 可能是挂载函数调用 var functionCallNode = ParseFunctionCall(); return functionCallNode; } - else + else { } + + int GetFlowType(SereinScriptLexer _lexer, ref int tokenCount) + { + int int_type; + while (true) + { + var tempToken = _lexer.PeekToken(tokenCount++); + + if (tempToken.Type == TokenType.Operator && tempToken.Value == "=") + { + var tempToken2 = _lexer.PeekToken(tokenCount - 2); + if (tempToken2.Type == TokenType.SquareBracketsRight) + { + int_type = 2; // 变量数组赋值 + break; + } + else // if (tempToken2.Type == TokenType.SquareBracketsRight) + { + int_type = 1; // 变量赋值 + break; + } + } + *//* if (tempToken.Type == TokenType.Semicolon) + { + var tempToken2 = _lexer.PeekToken(tokenCount); + if(tempToken2.Type == TokenType.ParenthesisRight) + { + int_type = 3; // 方法调用 + break; + } + }*//* + if (tempToken.Type == TokenType.ParenthesisLeft) // 本地函数调用 + { + int_type = 4; // 本地方法调用 + break; + } + + } + + return int_type; + } + return null; #region MyRegion - /*return null; + *//*return null; var _identifierPeekToken = _lexer.PeekToken(); if (_identifierPeekToken.Type == TokenType.Operator && _identifierPeekToken.Value == "=") { @@ -424,7 +1372,7 @@ namespace Serein.Script { var objNode = new ObjectMemberExpressionNode(objectNode, nodes).SetTokenInfo(objToken); return objNode; - }*/ + }*//* #endregion // 检查标识符后是否跟有左圆括号 @@ -438,22 +1386,23 @@ namespace Serein.Script { // 对象成员的获取 - return ParseMemberAccessOrAssignment(); + return ParseMemberAccessOrAssignment(); } else if (_tempToken.Type == TokenType.SquareBracketsLeft) { // 数组 index; 字典 key obj.Member[xxx]; return ParseCollectionIndex(); - + } else { // 不是函数调用,是变量赋值或其他 return ParseAssignment(); } + } - + /// /// 解析赋值行为 /// @@ -567,12 +1516,12 @@ namespace Serein.Script private ASTNode ParseClassDefinition() { var sb = new StringBuilder(); // 收集代码信息 - /* + *//* * 有两种定义类型的方式: * 1. class MyClass{} * 2. new class MyClass{} * 解析执行时,第二种方式定义的类,会顶掉其他地方创建的“MyClass”同名类型; - */ + *//* var coreStartRangeIndex = _lexer.GetIndex() - "class".Length; // 从“class”开始锚定代码范围 bool isOverlay = false; // 指示是否覆盖缓存中创建过的同名其它类型 @@ -668,7 +1617,7 @@ namespace Serein.Script _currentToken = _lexer.NextToken(); // 消耗数组名称 identifier // ParenthesisLeft if (_currentToken.Type != TokenType.SquareBracketsLeft) - throw new Exception("Expected '[' after function name"); + throw new Exception("数组操作需要 '[' 符号"); _currentToken = _lexer.NextToken(); // 消耗 "[" @@ -824,6 +1773,10 @@ namespace Serein.Script // 获取参数 while (true)// _currentToken.Type != TokenType.ParenthesisRight { + if (_currentToken.Type == TokenType.ParenthesisRight) + { + break; + } //var arg = Expression(); // 获取参数表达式 var arg = BooleanExpression(); // 获取参数表达式 arguments.Add(arg); @@ -840,12 +1793,12 @@ namespace Serein.Script //isBreak = true; break; // consume ";" } - /*if (_currentToken.Type == TokenType.Semicolon) // 提前结束 + *//*if (_currentToken.Type == TokenType.Semicolon) // 提前结束 { arguments.Add(arg); isBreak = true; break; // consume ";" - }*/ + }*//* //_currentToken = _lexer.NextToken(); // consume arg } //if(!isBreak) @@ -971,179 +1924,57 @@ namespace Serein.Script List body = new List(); while (_currentToken.Type != TokenType.BraceRight) { - body.Add(Statement()); // 解析循环体中的语句 + var node = Statement(); + if(node is not null) + { + body.Add(node); // 解析循环体中的语句 + } + if (_currentToken.Type == TokenType.Semicolon) + { + _currentToken = _lexer.NextToken(); // Consume ";" + } + + } _currentToken = _lexer.NextToken(); // Consume "}" return new WhileNode(condition, body).SetTokenInfo(_currentToken); } - /// - /// 顶层布尔表达式 - /// - /// - private ASTNode BooleanExpression() - { - ASTNode left = ComparisonExpression(); - while (_currentToken.Type == TokenType.Operator && - (_currentToken.Value == "&&" || _currentToken.Value == "||")) - { - string op = _currentToken.Value; - _currentToken = _lexer.NextToken(); - ASTNode right = ComparisonExpression(); - left = new BinaryOperationNode(left, op, right).SetTokenInfo(_currentToken); - } - return left; - } - /// - /// 比较表达式(==, !=, <, <=, >, >=) - /// - /// - private ASTNode ComparisonExpression() - { - ASTNode left = Expression(); - while (_currentToken.Type == TokenType.Operator && - (_currentToken.Value == "==" || _currentToken.Value == "!=" || - _currentToken.Value == "<" || _currentToken.Value == "<=" || - _currentToken.Value == ">" || _currentToken.Value == ">=")) - { - string op = _currentToken.Value; - _currentToken = _lexer.NextToken(); - ASTNode right = Expression(); - left = new BinaryOperationNode(left, op, right).SetTokenInfo(_currentToken); - } - - return left; - } - - /// - /// 加减 - /// - /// - private ASTNode Expression() - { - ASTNode left = Term(); - - while (_currentToken.Type == TokenType.Operator && - (_currentToken.Value == "+" || _currentToken.Value == "-")) - { - string op = _currentToken.Value; - _currentToken = _lexer.NextToken(); - ASTNode right = Term(); - left = new BinaryOperationNode(left, op, right).SetTokenInfo(_currentToken); - } - - return left; - } - - /// - /// 乘除 - /// - /// - private ASTNode Term() - { - ASTNode left = Factor(); - - while (_currentToken.Type == TokenType.Operator && - (_currentToken.Value == "*" || _currentToken.Value == "/")) - { - string op = _currentToken.Value; - _currentToken = _lexer.NextToken(); - ASTNode right = Factor(); - left = new BinaryOperationNode(left, op, right).SetTokenInfo(_currentToken); - } - - return left; - } /// /// 解析因子(Factor),用于处理基本的字面量、标识符、括号表达式等。 /// /// /// - private ASTNode Factor() + private ASTNode FactorTemp() { - - - #region 返回字面量 - if (_currentToken.Type == TokenType.Null) - { - _currentToken = _lexer.NextToken(); // 消耗 null - return new NullNode().SetTokenInfo(_currentToken); - } - if (_currentToken.Type == TokenType.Boolean) - { - var value = bool.Parse(_currentToken.Value); - _currentToken = _lexer.NextToken(); // 消耗布尔量 - return new BooleanNode(value).SetTokenInfo(_currentToken); - } - if (_currentToken.Type == TokenType.String) - { - var text = _currentToken.Value; - var node = new StringNode(text).SetTokenInfo(_currentToken); - _currentToken = _lexer.NextToken(); // 消耗字符串 - return node; - } - if (_currentToken.Type == TokenType.Char) - { - var text = _currentToken.Value; - _currentToken = _lexer.NextToken(); // 消耗Char - return new CharNode(text).SetTokenInfo(_currentToken); - } - if( _currentToken.Type == TokenType.InterpolatedString) - { - // 暂未实现插值字符串 - // 可能是插值字符串; - // let context = $"a{A}b{B}c"; - // let context = "a" + A + "b" + B + c; - _currentToken = _lexer.NextToken(); // 消耗字符串 - while (_currentToken.Type == TokenType.String) { - } - } - - if (_currentToken.Type == TokenType.NumberInt) - { - var value = int.Parse(_currentToken.Value); - _currentToken = _lexer.NextToken(); // 消耗 int 整型 - return new NumberIntNode(value).SetTokenInfo(_currentToken); - } - - if (_currentToken.Type == TokenType.NumberLong) - { - var value = long.Parse(_currentToken.Value); - _currentToken = _lexer.NextToken(); // 消耗 - return new NumberLongNode(value).SetTokenInfo(_currentToken); - } - - if (_currentToken.Type == TokenType.NumberFloat) - { - var value = float.Parse(_currentToken.Value); - _currentToken = _lexer.NextToken(); // 消耗数字 - return new NumberFloatNode(value).SetTokenInfo(_currentToken); - } - - if (_currentToken.Type == TokenType.NumberDouble) - { - var value = float.Parse(_currentToken.Value); - _currentToken = _lexer.NextToken(); // 消耗数字 - return new NumberDoubleNode(value).SetTokenInfo(_currentToken); - } - #endregion - // 标识符节点 if (_currentToken.Type == TokenType.Identifier) { var _identifierPeekToken = _lexer.PeekToken(); - if (_identifierPeekToken.Type is (TokenType.Dot and TokenType.ParenthesisLeft) or TokenType.Semicolon or TokenType.Comma) + if (_identifierPeekToken.Type is (TokenType.Dot and TokenType.ParenthesisLeft) + or TokenType.Semicolon + or TokenType.Comma + or TokenType.SquareBracketsRight) // 数组下标的"]",应该是正在获取数组索引 { // 不是 "." 号,也不是 "(" , 或是";",则是获取变量 var node = new IdentifierNode(_currentToken.Value).SetTokenInfo(_currentToken); // 获取变量 _currentToken = _lexer.NextToken(); // 消耗变量 return node; } + + if (_identifierPeekToken.Type == TokenType.SquareBracketsLeft) + { + // 数组下标语法 + //var functionCallNode = ParseFunctionCall(); + var sourceNode = new IdentifierNode(_currentToken.Value).SetTokenInfo(_currentToken); // 获取变量 + var coolectionNode = ParseCollectionIndex(sourceNode).SetTokenInfo(_currentToken); + return coolectionNode; + } if (_identifierPeekToken.Type == TokenType.ParenthesisLeft) { // 可能是挂载函数调用 @@ -1209,41 +2040,12 @@ namespace Serein.Script else { var node = nodes[^1]; - var objNode = new ObjectMemberExpressionNode(node).SetTokenInfo(objToken); + var objNode = new ExpressionNode(node).SetTokenInfo(objToken); return objNode; } - - - - /* var _identifierPeekToken = _lexer.PeekToken(); - // 该标识符是方法调用 - if (_identifierPeekToken.Type == TokenType.ParenthesisLeft) - { - // 可能是函数调用 - return ParseFunctionCall(); - } - - // 需要从该标识符调用另一个标识符 - if (_identifierPeekToken.Type == TokenType.Dot) - { - // 可能是成员访问或成员赋值 - return ParseMemberAccessOrAssignment(); // 二元操作中获取对象成员 - } - - - // 数组 index; 字典 key obj.Member[xxx]; - if (_identifierPeekToken.Type == TokenType.SquareBracketsLeft) - { - return ParseCollectionIndex(); - } - - _currentToken = _lexer.NextToken(); // 消耗标识符 - return new IdentifierNode(identifier.ToString()).SetTokenInfo(_currentToken);*/ } - - - // 方法调用 + // 嵌套表达式 if (_currentToken.Type == TokenType.ParenthesisLeft) { _currentToken = _lexer.NextToken(); // 消耗 "(" @@ -1262,11 +2064,76 @@ namespace Serein.Script return ParseObjectInstantiation(); } - + #region 返回字面量 + if (_currentToken.Type == TokenType.Null) + { + _currentToken = _lexer.NextToken(); // 消耗 null + return new NullNode().SetTokenInfo(_currentToken); + } + if (_currentToken.Type == TokenType.Boolean) + { + var value = bool.Parse(_currentToken.Value); + _currentToken = _lexer.NextToken(); // 消耗布尔量 + return new BooleanNode(value).SetTokenInfo(_currentToken); + } + if (_currentToken.Type == TokenType.String) + { + var text = _currentToken.Value; + var node = new StringNode(text).SetTokenInfo(_currentToken); + _currentToken = _lexer.NextToken(); // 消耗字符串 + return node; + } + if (_currentToken.Type == TokenType.Char) + { + var text = _currentToken.Value; + _currentToken = _lexer.NextToken(); // 消耗Char + return new CharNode(text).SetTokenInfo(_currentToken); + } + if (_currentToken.Type == TokenType.InterpolatedString) + { + // 暂未实现插值字符串 + // 可能是插值字符串; + // let context = $"a{A}b{B}c"; + // let context = "a" + A + "b" + B + c; + _currentToken = _lexer.NextToken(); // 消耗字符串 + while (_currentToken.Type == TokenType.String) + { + } + } + + if (_currentToken.Type == TokenType.NumberInt) + { + var value = int.Parse(_currentToken.Value); + _currentToken = _lexer.NextToken(); // 消耗 int 整型 + return new NumberIntNode(value).SetTokenInfo(_currentToken); + } + + if (_currentToken.Type == TokenType.NumberLong) + { + var value = long.Parse(_currentToken.Value); + _currentToken = _lexer.NextToken(); // 消耗 + return new NumberLongNode(value).SetTokenInfo(_currentToken); + } + + if (_currentToken.Type == TokenType.NumberFloat) + { + var value = float.Parse(_currentToken.Value); + _currentToken = _lexer.NextToken(); // 消耗数字 + return new NumberFloatNode(value).SetTokenInfo(_currentToken); + } + + if (_currentToken.Type == TokenType.NumberDouble) + { + var value = float.Parse(_currentToken.Value); + _currentToken = _lexer.NextToken(); // 消耗数字 + return new NumberDoubleNode(value).SetTokenInfo(_currentToken); + } + #endregion + - throw new Exception($"在Expression().Factor()遇到意外的 Token Type ,{_currentToken.Type} {_currentToken.Value} " ); - } + }*/ + #endregion } } diff --git a/Serein.Script/SereinScriptTypeAnalysis.cs b/Serein.Script/SereinScriptTypeAnalysis.cs index 28748fa..efc98bf 100644 --- a/Serein.Script/SereinScriptTypeAnalysis.cs +++ b/Serein.Script/SereinScriptTypeAnalysis.cs @@ -1,6 +1,7 @@ using Serein.Library; using Serein.Library.Utils; using Serein.Script.Node; +using Serein.Script.Node.FlowControl; using Serein.Script.Symbol; using System; using System.Collections.Generic; @@ -30,9 +31,21 @@ namespace Serein.Script } + public void LoadSymbol(Dictionary identifierNodes) + { + foreach(var kvp in identifierNodes) + { + var name = kvp.Key; + var type = kvp.Value; + var identifierNode = new IdentifierNode(name); + NodeSymbolInfos[identifierNode] = type; + } + } + + public void AnalysisProgramNode(ProgramNode astNode) { - NodeSymbolInfos.Clear(); + //NodeSymbolInfos.Clear(); for (int i = 0; i < astNode.Statements.Count; i++) { var node = astNode.Statements[i]; @@ -59,103 +72,6 @@ namespace Serein.Script - /// - /// 类型分析 - /// - /// - /// - private void Analysis1(ASTNode node) - { - switch (node) - { - case ProgramNode programNode: // 程序开始节点 - break; - case ReturnNode returnNode: // 程序退出节点 - Analysis(returnNode); // 解析变量定义的类型 - break; - case NullNode nullNode: // null - case CharNode charNode: // char字面量 - case StringNode stringNode: // 字符串字面量 - case BooleanNode booleanNode: // 布尔值字面量 - case NumberIntNode numberIntNode: // int整型数值字面量 - case NumberLongNode numberLongNode: // long整型数值字面量 - case NumberFloatNode numberFloatNode: // float浮点数值字面量 - case NumberDoubleNode numberDoubleNode: // double浮点数值字面量 - Analysis(node); - break; - case IdentifierNode identifierNode: // 变量定义 - void AnalysisIdentifierNode(IdentifierNode identifierNode) - { - Analysis(identifierNode); // 解析变量定义的类型 - } - AnalysisIdentifierNode(identifierNode); - break; - case IfNode ifNode: // if语句结构 - void AnalysisIfNode(IfNode ifNode) - { - Analysis(ifNode); - - } - AnalysisIfNode(ifNode); - break; - case WhileNode whileNode: // while语句结构 - void AnalysisWhileNode(WhileNode whileNode) - { - Analysis(whileNode); - } - AnalysisWhileNode(whileNode); - break; - case AssignmentNode assignmentNode: // 对象赋值语句(let x;默认赋值null。默认类型object) - void AnalysisAssignmentNode(AssignmentNode assignmentNode) - { - Analysis(assignmentNode); - } - AnalysisAssignmentNode(assignmentNode); - break; - case BinaryOperationNode binaryOperationNode: // 二元运算操作 - void AnalysisBinaryOperationNode(BinaryOperationNode binaryOperationNode) - { - Analysis(binaryOperationNode); - } - AnalysisBinaryOperationNode(binaryOperationNode); - break; - case CollectionIndexNode collectionIndexNode: // 集合类型操作 - void AnalysisCollectionIndexNode(CollectionIndexNode collectionIndexNode) - { - Analysis(collectionIndexNode); - } - AnalysisCollectionIndexNode(collectionIndexNode); - break; - case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义 - Analysis(classTypeDefinitionNode); - break; - case ObjectInstantiationNode objectInstantiationNode: // 类型实例化 - Analysis(objectInstantiationNode); - break; - case ObjectMemberExpressionNode objectMemberExpressionNode: // 类型表达式(链式调用) - Analysis(objectMemberExpressionNode); - break; - case MemberAccessNode memberAccessNode: // 对象成员访问 - Analysis(memberAccessNode); - break; - case MemberAssignmentNode memberAssignmentNode: // 对象成员赋值 - void AnalysisMemberAssignmentNode(MemberAssignmentNode memberAssignmentNode) - { - Analysis(memberAssignmentNode); - } - AnalysisMemberAssignmentNode(memberAssignmentNode); - break; - case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用 - Analysis(memberFunctionCallNode); - break; - case FunctionCallNode functionCallNode: // 外部挂载的函数调用 - Analysis(functionCallNode); - break; - default: // 未定义的节点类型 - break; - } - } - /// /// 类型获取 /// @@ -302,6 +218,20 @@ namespace Serein.Script return resultType; } return AnalysisCollectionIndexNode(collectionIndexNode); + case CollectionAssignmentNode collectionAssignmentNode: // 集合赋值操作 + Type AnalysisCollectionAssignmentNode(CollectionAssignmentNode collectionAssignmentNode) + { + var resultType = Analysis(collectionAssignmentNode.Collection); // 分析集合返回返回类型 + var valueType = Analysis(collectionAssignmentNode.Value); // 分析赋值的类型 + if (!resultType.IsAssignableFrom(valueType)) + throw new Exception($"类型 {resultType} 不支持索引操作"); + + NodeSymbolInfos[collectionAssignmentNode.Collection] = resultType; + NodeSymbolInfos[collectionAssignmentNode.Value] = valueType; + NodeSymbolInfos[collectionAssignmentNode] = typeof(void); // 赋值语句不产生类型 + return typeof(void); + } + return AnalysisCollectionAssignmentNode(collectionAssignmentNode); case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义 Type AnalysisClassTypeDefinitionNode(ClassTypeDefinitionNode classTypeDefinitionNode) { @@ -331,18 +261,18 @@ namespace Serein.Script return resultType; } return AnalysisObjectInstantiationNode(objectInstantiationNode); - case ObjectMemberExpressionNode objectMemberExpressionNode: // 类型表达式(链式调用) - Type AnalysisObjectMemberExpressionNode(ObjectMemberExpressionNode objectMemberExpressionNode) + case ExpressionNode expressionNode: // 类型表达式(链式调用) + Type AnalysisObjectMemberExpressionNode(ExpressionNode expressionNode) { // 1. 对象成员获取 MemberAccessNode // 2. 对象方法调用 MemberFunctionCallNode // 3. 对象集合成员获取 CollectionIndexNode - Type? resultType = Analysis(objectMemberExpressionNode.Value); - NodeSymbolInfos[objectMemberExpressionNode.Value] = resultType; - NodeSymbolInfos[objectMemberExpressionNode] = resultType; + Type? resultType = Analysis(expressionNode.Value); + NodeSymbolInfos[expressionNode.Value] = resultType; + NodeSymbolInfos[expressionNode] = resultType; return resultType; } - return AnalysisObjectMemberExpressionNode(objectMemberExpressionNode); + return AnalysisObjectMemberExpressionNode(expressionNode); case MemberAccessNode memberAccessNode: // 对象成员访问 Type AnalysisMemberAccessNode(MemberAccessNode memberAccessNode) { @@ -416,6 +346,106 @@ namespace Serein.Script } + + + /// + /// 类型分析 + /// + /// + /// + private void Analysis1(ASTNode node) + { + switch (node) + { + case ProgramNode programNode: // 程序开始节点 + break; + case ReturnNode returnNode: // 程序退出节点 + Analysis(returnNode); // 解析变量定义的类型 + break; + case NullNode nullNode: // null + case CharNode charNode: // char字面量 + case StringNode stringNode: // 字符串字面量 + case BooleanNode booleanNode: // 布尔值字面量 + case NumberIntNode numberIntNode: // int整型数值字面量 + case NumberLongNode numberLongNode: // long整型数值字面量 + case NumberFloatNode numberFloatNode: // float浮点数值字面量 + case NumberDoubleNode numberDoubleNode: // double浮点数值字面量 + Analysis(node); + break; + case IdentifierNode identifierNode: // 变量定义 + void AnalysisIdentifierNode(IdentifierNode identifierNode) + { + Analysis(identifierNode); // 解析变量定义的类型 + } + AnalysisIdentifierNode(identifierNode); + break; + case IfNode ifNode: // if语句结构 + void AnalysisIfNode(IfNode ifNode) + { + Analysis(ifNode); + + } + AnalysisIfNode(ifNode); + break; + case WhileNode whileNode: // while语句结构 + void AnalysisWhileNode(WhileNode whileNode) + { + Analysis(whileNode); + } + AnalysisWhileNode(whileNode); + break; + case AssignmentNode assignmentNode: // 对象赋值语句(let x;默认赋值null。默认类型object) + void AnalysisAssignmentNode(AssignmentNode assignmentNode) + { + Analysis(assignmentNode); + } + AnalysisAssignmentNode(assignmentNode); + break; + case BinaryOperationNode binaryOperationNode: // 二元运算操作 + void AnalysisBinaryOperationNode(BinaryOperationNode binaryOperationNode) + { + Analysis(binaryOperationNode); + } + AnalysisBinaryOperationNode(binaryOperationNode); + break; + case CollectionIndexNode collectionIndexNode: // 集合类型操作 + void AnalysisCollectionIndexNode(CollectionIndexNode collectionIndexNode) + { + Analysis(collectionIndexNode); + } + AnalysisCollectionIndexNode(collectionIndexNode); + break; + case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义 + Analysis(classTypeDefinitionNode); + break; + case ObjectInstantiationNode objectInstantiationNode: // 类型实例化 + Analysis(objectInstantiationNode); + break; + case ExpressionNode expressionNode: // 类型表达式(链式调用) + Analysis(expressionNode.Value); + break; + case MemberAccessNode memberAccessNode: // 对象成员访问 + Analysis(memberAccessNode); + break; + case MemberAssignmentNode memberAssignmentNode: // 对象成员赋值 + void AnalysisMemberAssignmentNode(MemberAssignmentNode memberAssignmentNode) + { + Analysis(memberAssignmentNode); + } + AnalysisMemberAssignmentNode(memberAssignmentNode); + break; + case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用 + Analysis(memberFunctionCallNode); + break; + case FunctionCallNode functionCallNode: // 外部挂载的函数调用 + Analysis(functionCallNode); + break; + default: // 未定义的节点类型 + break; + } + } + + private void Analysis2(ASTNode node) { switch (node) @@ -450,13 +480,15 @@ namespace Serein.Script break; case BinaryOperationNode binaryOperationNode: // 二元运算操作 break; + case CollectionAssignmentNode collectionAssignmentNode: + break; case CollectionIndexNode collectionIndexNode: // 集合类型操作 break; case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义 break; case ObjectInstantiationNode objectInstantiationNode: // 类型实例化 break; - case ObjectMemberExpressionNode objectMemberExpressionNode: // 类型表达式(链式调用) + case ExpressionNode expressionNode: // 类型表达式(链式调用) break; case MemberAccessNode memberAccessNode: // 对象成员访问 break; @@ -472,6 +504,9 @@ namespace Serein.Script } + + + /// /// 获取某个集合类型支持的索引参数类型 /// diff --git a/Workbench/Node/Junction/JunctionControlBase.cs b/Workbench/Node/Junction/JunctionControlBase.cs index 2fbdaf8..029c1f8 100644 --- a/Workbench/Node/Junction/JunctionControlBase.cs +++ b/Workbench/Node/Junction/JunctionControlBase.cs @@ -17,6 +17,8 @@ using Serein.Workbench.Tool; using System.ComponentModel; using System.Diagnostics; using Serein.Library.Api; +using Serein.Workbench.Node.ViewModel; +using Serein.Workbench.Themes; namespace Serein.Workbench.Node.View { @@ -39,6 +41,7 @@ namespace Serein.Workbench.Node.View return pen; } } + /// /// 入参控件 @@ -135,7 +138,6 @@ namespace Serein.Workbench.Node.View { AddOrRemoveParamsAction = RemoveParamAsync; this.Dispatcher.Invoke(InvalidateVisual);// 触发一次重绘 - } }); } @@ -157,11 +159,11 @@ namespace Serein.Workbench.Node.View - private void AddParamAsync() + private void AddParamAsync() // 以当前选定入参连接器增加新的入参 { this.MyNode.Env.FlowEdit.ChangeParameter(MyNode.Guid, true, ArgIndex); } - private void RemoveParamAsync() + private void RemoveParamAsync() // 移除当前选定的入参连接器 { this.MyNode.Env.FlowEdit.ChangeParameter(MyNode.Guid, false, ArgIndex); } @@ -194,18 +196,41 @@ namespace Serein.Workbench.Node.View #region 控件属性,所在的节点 - public static readonly DependencyProperty NodeProperty = + /* public static readonly DependencyProperty NodeProperty = DependencyProperty.Register(nameof(MyNode), typeof(IFlowNode), typeof(JunctionControlBase), new PropertyMetadata(default(IFlowNode))); - //public NodeModelBase NodeModel; - /// - /// 所在的节点 - /// public IFlowNode MyNode { get { return (IFlowNode)GetValue(NodeProperty); } set { SetValue(NodeProperty, value); } } +*/ + + /// + /// 对应的节点Control View Model + /// + public NodeControlViewModelBase NodeViewModel + { + get { return (NodeControlViewModelBase)GetValue(NodeViewModelProperty); } + set { SetValue(NodeViewModelProperty, value); } + } + + public static readonly DependencyProperty NodeViewModelProperty = + DependencyProperty.Register(nameof(NodeViewModel), typeof(NodeControlViewModelBase), typeof(JunctionControlBase), new PropertyMetadata(default(IFlowNode))); + + + /// + /// 对应的节点Guid + /// + public string NodeGuid + { + get + { + return NodeViewModel?.NodeModel.Guid ?? string.Empty; + } + } + + #endregion #region 控件属性,连接器类型 @@ -253,13 +278,8 @@ namespace Serein.Workbench.Node.View { if(_isMouseOver != value) { - if(flowNodeService is not null) - { - - flowNodeService.ConnectingData.CurrentJunction = this; - } + _isMouseOver = value; - InvalidateVisual(); } } @@ -326,7 +346,11 @@ namespace Serein.Workbench.Node.View //if (IsMouseOver) return; IsMouseOver = true; - + + flowNodeService.ConnectingData.CurrentJunction = this; + InvalidateVisual(); + + //Debug.WriteLine(NodeGuid); //this.InvalidateVisual(); } @@ -339,7 +363,8 @@ namespace Serein.Workbench.Node.View { IsMouseOver = false; e.Handled = true; - + flowNodeService.ConnectingData.CurrentJunction = this; + InvalidateVisual(); } diff --git a/Workbench/Node/Junction/JunctionData.cs b/Workbench/Node/Junction/JunctionData.cs index 7acb33b..aa270b0 100644 --- a/Workbench/Node/Junction/JunctionData.cs +++ b/Workbench/Node/Junction/JunctionData.cs @@ -86,7 +86,7 @@ namespace Serein.Workbench.Node.View } - if (!StartJunction.MyNode.Equals(CurrentJunction.MyNode) + if (!StartJunction.NodeGuid.Equals(CurrentJunction.NodeGuid) && StartJunction.JunctionType.IsCanConnection(CurrentJunction.JunctionType)) { return true; @@ -139,23 +139,5 @@ namespace Serein.Workbench.Node.View } - public static class GlobalJunctionData1 - { - //private static ConnectingData? myGlobalData; - //private static object _lockObj = new object(); - - /// - /// 创建节点之间控制点的连接行为 - /// - public static ConnectingData MyGlobalConnectingData { get; } = new ConnectingData(); - - /// - /// 删除连接视觉效果 - /// - public static void OK() - { - MyGlobalConnectingData.Reset(); - } - } #endregion } diff --git a/Workbench/Node/Junction/View/ArgJunctionControl.cs b/Workbench/Node/Junction/View/ArgJunctionControl.cs index 6ef6927..a16dc07 100644 --- a/Workbench/Node/Junction/View/ArgJunctionControl.cs +++ b/Workbench/Node/Junction/View/ArgJunctionControl.cs @@ -15,7 +15,7 @@ namespace Serein.Workbench.Node.View #region 控件属性,对应的参数 public static readonly DependencyProperty ArgIndexProperty = - DependencyProperty.Register("ArgIndex", typeof(int), typeof(ArgJunctionControl), new PropertyMetadata(default(int))); + DependencyProperty.Register(nameof(ArgIndex), typeof(int), typeof(ArgJunctionControl), new PropertyMetadata(default(int))); /// /// 所在的节点 diff --git a/Workbench/Node/View/ActionNodeControl.xaml b/Workbench/Node/View/ActionNodeControl.xaml index 69ad89d..8466865 100644 --- a/Workbench/Node/View/ActionNodeControl.xaml +++ b/Workbench/Node/View/ActionNodeControl.xaml @@ -62,15 +62,15 @@ - + - + - + - + diff --git a/Workbench/Node/View/ActionNodeControl.xaml.cs b/Workbench/Node/View/ActionNodeControl.xaml.cs index 5cfa4f0..be84931 100644 --- a/Workbench/Node/View/ActionNodeControl.xaml.cs +++ b/Workbench/Node/View/ActionNodeControl.xaml.cs @@ -18,10 +18,10 @@ namespace Serein.Workbench.Node.View { DataContext = viewModel; InitializeComponent(); - if(ExecuteJunctionControl.MyNode != null) + /*if(ExecuteJunctionControl.MyNode != null) { ExecuteJunctionControl.MyNode.Guid = viewModel.NodeModel.Guid; - } + }*/ } /// diff --git a/Workbench/Node/View/ConditionNodeControl.xaml b/Workbench/Node/View/ConditionNodeControl.xaml index ff302ea..8c0184d 100644 --- a/Workbench/Node/View/ConditionNodeControl.xaml +++ b/Workbench/Node/View/ConditionNodeControl.xaml @@ -37,11 +37,11 @@ - + - + @@ -55,7 +55,7 @@ - + - + diff --git a/Workbench/Node/View/ConnectionControl.cs b/Workbench/Node/View/ConnectionControl.cs index ef5423f..2fa7136 100644 --- a/Workbench/Node/View/ConnectionControl.cs +++ b/Workbench/Node/View/ConnectionControl.cs @@ -3,6 +3,7 @@ using Serein.Library.Api; using Serein.Workbench.Api; using Serein.Workbench.Extension; using Serein.Workbench.Tool; +using Serein.Workbench.ViewModels; using System; using System.Net; using System.Windows; @@ -260,17 +261,17 @@ namespace Serein.Workbench.Node.View // Canvas.Children.Remove(BezierLine); - var env = Start.MyNode.Env; - var canvasGuid = Start.MyNode.CanvasDetails.Guid; + var env = App.GetService(); + var canvasGuid = ((FlowCanvasViewModel)(Canvas.DataContext)).Model.Guid; var jct = Start.JunctionType.ToConnectyionType(); var jctEnd = End.JunctionType.ToConnectyionType(); if (jct == JunctionOfConnectionType.Invoke) { - env.FlowEdit.RemoveInvokeConnect(canvasGuid, Start.MyNode.Guid, End.MyNode.Guid, InvokeType); + env.FlowEdit.RemoveInvokeConnect(canvasGuid, Start.NodeGuid, End.NodeGuid, InvokeType); } else if (jct == JunctionOfConnectionType.Arg) { - env.FlowEdit.RemoveArgSourceConnect(canvasGuid, Start.MyNode.Guid, End.MyNode.Guid, ArgIndex); + env.FlowEdit.RemoveArgSourceConnect(canvasGuid, Start.NodeGuid, End.NodeGuid, ArgIndex); } } @@ -279,10 +280,10 @@ namespace Serein.Workbench.Node.View /// public void Topping() { - var env = Start.MyNode.Env; + var env = App.GetService(); if (Start.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke) { - env.FlowEdit.SetConnectPriorityInvoke(Start.MyNode.Guid, End.MyNode.Guid, InvokeType); + env.FlowEdit.SetConnectPriorityInvoke(Start.NodeGuid, End.NodeGuid, InvokeType); } } diff --git a/Workbench/Node/View/ExpOpNodeControl.xaml b/Workbench/Node/View/ExpOpNodeControl.xaml index ac59910..487b07f 100644 --- a/Workbench/Node/View/ExpOpNodeControl.xaml +++ b/Workbench/Node/View/ExpOpNodeControl.xaml @@ -25,11 +25,11 @@ - + - + @@ -38,9 +38,9 @@ - + - + diff --git a/Workbench/Node/View/FlipflopNodeControl.xaml b/Workbench/Node/View/FlipflopNodeControl.xaml index e6bf277..3f423d5 100644 --- a/Workbench/Node/View/FlipflopNodeControl.xaml +++ b/Workbench/Node/View/FlipflopNodeControl.xaml @@ -43,16 +43,16 @@ - + - + - + @@ -74,7 +74,7 @@ - + diff --git a/Workbench/Node/View/FlowCallNodeControl.xaml b/Workbench/Node/View/FlowCallNodeControl.xaml index f6c2984..7ff62f7 100644 --- a/Workbench/Node/View/FlowCallNodeControl.xaml +++ b/Workbench/Node/View/FlowCallNodeControl.xaml @@ -64,7 +64,7 @@ - + @@ -109,7 +109,7 @@ - + diff --git a/Workbench/Node/View/GlobalDataControl.xaml b/Workbench/Node/View/GlobalDataControl.xaml index d13189a..2bbd8b1 100644 --- a/Workbench/Node/View/GlobalDataControl.xaml +++ b/Workbench/Node/View/GlobalDataControl.xaml @@ -35,11 +35,11 @@ - + - + diff --git a/Workbench/Node/View/NetScriptNodeControl.xaml b/Workbench/Node/View/NetScriptNodeControl.xaml index 10d3a8f..b111715 100644 --- a/Workbench/Node/View/NetScriptNodeControl.xaml +++ b/Workbench/Node/View/NetScriptNodeControl.xaml @@ -30,11 +30,11 @@ - + - + diff --git a/Workbench/Node/View/ScriptNodeControl.xaml b/Workbench/Node/View/ScriptNodeControl.xaml index 4117c7b..8d44b3c 100644 --- a/Workbench/Node/View/ScriptNodeControl.xaml +++ b/Workbench/Node/View/ScriptNodeControl.xaml @@ -29,11 +29,11 @@ - + - + @@ -54,9 +54,8 @@ - - + @@ -68,11 +67,11 @@ - + - + diff --git a/Workbench/Node/View/UINodeControl.xaml b/Workbench/Node/View/UINodeControl.xaml index 9c5ec8f..2212551 100644 --- a/Workbench/Node/View/UINodeControl.xaml +++ b/Workbench/Node/View/UINodeControl.xaml @@ -25,7 +25,7 @@ - + diff --git a/Workbench/Node/ViewModel/FlowCallNodeControlViewModel.cs b/Workbench/Node/ViewModel/FlowCallNodeControlViewModel.cs index 9543b92..b3df1b6 100644 --- a/Workbench/Node/ViewModel/FlowCallNodeControlViewModel.cs +++ b/Workbench/Node/ViewModel/FlowCallNodeControlViewModel.cs @@ -83,22 +83,32 @@ namespace Serein.Workbench.Node.ViewModel } - + /// + /// 选择画布发生改变 + /// + /// partial void OnSelectCanvasChanged(FlowCanvasViewModel value) { - FlowCallNode.ResetTargetNode(); + FlowCallNode.ResetTargetNode(); // 改变画布直接重置 } + /// + /// 选择的节点发生改变 + /// + /// partial void OnSelectNodeChanged(IFlowNode value) { if(value is null) { - FlowCallNode.ResetTargetNode(); + FlowCallNode.ResetTargetNode(); // 如果是不选择了,则重置一下 return; } - FlowCallNode.SetTargetNode(value.Guid); + FlowCallNode.SetTargetNode(value.Guid); // 重新设置目标节点 } + /// + /// 刷新可选画布 + /// private void RershCanvass() { var canvass = flowNodeService.FlowCanvass.Select(f => (FlowCanvasViewModel)f.DataContext).ToArray(); // .Where(f => f.Model.PublicNodes.Count > 0) diff --git a/Workbench/Services/FlowNodeService.cs b/Workbench/Services/FlowNodeService.cs index 2071bdf..6fd2d6a 100644 --- a/Workbench/Services/FlowNodeService.cs +++ b/Workbench/Services/FlowNodeService.cs @@ -345,10 +345,6 @@ namespace Serein.Workbench.Services } #endregion - //if (nodeModel.ControlType == NodeControlType.FlowCall) - //{ - // Console.WriteLine("test"); - //} #region 创建控件 diff --git a/Workbench/Themes/MethodDetailsControl.xaml b/Workbench/Themes/MethodDetailsControl.xaml index 8258f8e..82d0a21 100644 --- a/Workbench/Themes/MethodDetailsControl.xaml +++ b/Workbench/Themes/MethodDetailsControl.xaml @@ -19,13 +19,13 @@