diff --git a/Library/FlowNode/DelegateDetails.cs b/Library/FlowNode/DelegateDetails.cs index eb34fbe..23f6049 100644 --- a/Library/FlowNode/DelegateDetails.cs +++ b/Library/FlowNode/DelegateDetails.cs @@ -1,10 +1,6 @@ using Serein.Library.Utils; using System; -using System.Collections.Generic; -using System.Linq; using System.Reflection; -using System.Runtime.CompilerServices; -using System.Text; using System.Threading.Tasks; using static Serein.Library.Utils.EmitHelper; @@ -54,7 +50,11 @@ namespace Serein.Library /// /// 集合赋值 /// - CollectionSetter + CollectionSetter, + /// + /// 数组创建 + /// + ArrayCreate, } /// @@ -172,6 +172,12 @@ namespace Serein.Library this.emitType = EmitType.CollectionGetter; collectionGetter = EmitHelper.CreateCollectionGetter(type); } + else if (emitType == EmitType.ArrayCreate) + { + Func func = EmitHelper.CreateArrayFactory(type); + this.arrayCreatefunc = func; + this.emitType = EmitType.ArrayCreate; + } else { throw new NotSupportedException("错误的构建类型"); @@ -179,8 +185,8 @@ namespace Serein.Library } + - private Func collectionGetter= null; @@ -195,6 +201,8 @@ namespace Serein.Library private Func methodTask = null; private Func methodInvoke = null; + private Func arrayCreatefunc = null; + /*/// /// 更新委托方法 @@ -260,10 +268,17 @@ namespace Serein.Library collectionSetter(instance, args[0], args[1]); return null; } - else + else if(emitType == EmitType.ArrayCreate) { - throw new NotSupportedException("当前委托类型不支持 InvokeAsync 方法。请使用其他方法调用。"); + if(args[0] is int count) + { + return arrayCreatefunc(count); + } + + } + throw new NotSupportedException("当前委托类型不支持 InvokeAsync 方法。请使用其他方法调用。"); + } private async Task MethodInvoke(object instance, object[] args) diff --git a/Library/Utils/EmitHelper.cs b/Library/Utils/EmitHelper.cs index 870f9d9..b1933b1 100644 --- a/Library/Utils/EmitHelper.cs +++ b/Library/Utils/EmitHelper.cs @@ -226,10 +226,8 @@ namespace Serein.Library.Utils }; } - - /// - /// 创建字段 Getter 委托:Func<object, object> + /// 构建字段 Getter 委托:Func<object, object> /// public static Func CreateFieldGetter(FieldInfo fieldInfo) { @@ -271,7 +269,7 @@ namespace Serein.Library.Utils } /// - /// 创建字段 Setter 委托:Action<object, object> + /// 构建字段 Setter 委托:Action<object, object> /// public static Action CreateFieldSetter(FieldInfo fieldInfo) { @@ -315,7 +313,7 @@ namespace Serein.Library.Utils } /// - /// 创建属性 Getter 委托:Func<object, object> + /// 构建属性 Getter 委托:Func<object, object> /// public static Func CreatePropertyGetter(PropertyInfo propertyInfo) { @@ -357,7 +355,7 @@ namespace Serein.Library.Utils } /// - /// 创建属性 Setter 委托:Action<object, object> + /// 构建属性 Setter 委托:Action<object, object> /// public static Action CreatePropertySetter(PropertyInfo propertyInfo) { @@ -402,9 +400,40 @@ namespace Serein.Library.Utils return (Action)method.CreateDelegate(typeof(Action)); } + /// + /// 构建数组创建委托:Func<int, object[]> + /// + /// + /// + /// + + public static Func CreateArrayFactory(Type elementType) + { + if (elementType == null) throw new ArgumentNullException(nameof(elementType)); + + var arrayType = elementType.MakeArrayType(); + + var dm = new DynamicMethod( + $"NewArray_{elementType.Name}", + typeof(object), // 返回 object + new[] { typeof(int) }, // 参数:length + typeof(EmitHelper).Module, + true); + + var il = dm.GetILGenerator(); + + + il.Emit(OpCodes.Ldarg_0); // length + il.Emit(OpCodes.Newarr, elementType); // new T[length] + il.Emit(OpCodes.Ret); // 返回 T[] + + return (Func)dm.CreateDelegate(typeof(Func)); + } + + /// - /// 创建集合赋值委托:Action<object, object, object> + /// 构建集合赋值委托:Action<object, object, object> /// /// /// @@ -474,9 +503,8 @@ namespace Serein.Library.Utils } - /// - /// 创建集合获取委托:Func<object, object, object> + /// 构建集合获取委托:Func<object, object, object> /// /// /// diff --git a/Library/Utils/TypeHelper.cs b/Library/Utils/TypeHelper.cs index dc7927d..063cead 100644 --- a/Library/Utils/TypeHelper.cs +++ b/Library/Utils/TypeHelper.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.Linq; using System.Text; namespace Serein.Library.Utils @@ -173,8 +174,52 @@ namespace Serein.Library.Utils } + /// + /// 发掘类型中的基类 + /// + /// + /// + public static Type? FindCommonBaseType(Type[] types) + { + if (types.Length == 0) + return null; + + Type? baseType = types[0]; + + foreach (var type in types.Skip(1)) + { + baseType = FindCommonBaseType(baseType, type); + if (baseType == typeof(object)) + break; + } + + return baseType; + } + + /// + /// 查找父类 + /// + /// + /// + /// + private static Type FindCommonBaseType(Type a, Type b) + { + // 如果相等,直接返回 + if (a == b) return a; + + // 向上查找父类链,找第一个 b.IsAssignableFrom(base) + var current = a; + while (current != null && current != typeof(object)) + { + if (current.IsAssignableFrom(b)) + return current; + + current = current.BaseType!; + } + + return typeof(object); + } + - - } } diff --git a/Serein.Script/Node/ArrayDefintionNode.cs b/Serein.Script/Node/ArrayDefintionNode.cs new file mode 100644 index 0000000..bab54a1 --- /dev/null +++ b/Serein.Script/Node/ArrayDefintionNode.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Serein.Script.Node +{ + /// + /// 数组定义节点 + /// arr = [1, 2, 3, 4, 5]; + /// arr = ["A","B","C"]; + /// + internal class ArrayDefintionNode : ASTNode + { + /// + /// 数组子项 + /// + public List Elements { get; } = new List(); + + public ArrayDefintionNode(List elements) + { + Elements = elements; + } + + } +} diff --git a/Serein.Script/SereinScriptInterpreter.cs b/Serein.Script/SereinScriptInterpreter.cs index c7d723d..dabdccf 100644 --- a/Serein.Script/SereinScriptInterpreter.cs +++ b/Serein.Script/SereinScriptInterpreter.cs @@ -175,6 +175,39 @@ namespace Serein.Script return result; } return await InterpreterCollectionIndexNodeAsync(context, collectionIndexNode); + case ArrayDefintionNode arrayDefintionNode: + async Task InterpreterArrayDefintionNodeAsync(ArrayDefintionNode arrayDefintionNode) + { + var elementNodes = arrayDefintionNode.Elements; + var elementCount = elementNodes.Count; + if(elementCount == 0) + { + return Array.Empty(); + } + /*var arrayType = symbolInfos[arrayDefintionNode]; // 从 symbolInfos 中获取数组类型( T[]) + var eleType = arrayType.MakeArrayType();*/ + /*if (!ASTDelegateDetails.TryGetValue(arrayDefintionNode, out DelegateDetails? delegateDetails)) + { + delegateDetails = new DelegateDetails(symbolInfos[elementNodes[0]], DelegateDetails.EmitType.ArrayCreate); + ASTDelegateDetails[arrayDefintionNode] = delegateDetails; + }*/ + //var arrobj = await delegateDetails.InvokeAsync(null, [elementCount]); + + var elementType1 = symbolInfos[elementNodes[0]]; + var array = Array.CreateInstance(elementType1, elementCount); + for (int i = 0; i < elementNodes.Count; i++) + { + var elementNode = elementNodes[i]; + var elementType = symbolInfos[elementNode]; + var value = await InterpretAsync(context, elementNode); + var c = Convert.ChangeType(value, elementType); + array.SetValue(c, i); + //array[i] = value; + } + return array; + + } + return await InterpreterArrayDefintionNodeAsync(arrayDefintionNode); case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义 void InterpreterClassTypeDefinitionNode(IScriptInvokeContext context, ClassTypeDefinitionNode classTypeDefinitionNode) { diff --git a/Serein.Script/SereinScriptLexer.cs b/Serein.Script/SereinScriptLexer.cs index 619701b..26cbf3d 100644 --- a/Serein.Script/SereinScriptLexer.cs +++ b/Serein.Script/SereinScriptLexer.cs @@ -123,7 +123,7 @@ public override string ToString() { - return $"token in {Row} row, type is \"{Type}\", value is \"{Value}\"."; + return $"token in {Row} row, type is \"{Type}\", value is \"{Value}\""; } } diff --git a/Serein.Script/SereinScriptParser.cs b/Serein.Script/SereinScriptParser.cs index aa51a7b..7d49aec 100644 --- a/Serein.Script/SereinScriptParser.cs +++ b/Serein.Script/SereinScriptParser.cs @@ -117,18 +117,19 @@ namespace Serein.Script } } #endregion - #region 生成 ASTNode + + #region 生成赋值语句/一般语句的ASTNode if (isAssignment) { // 以赋值语句的形式进行处理 - var assignmentNode = ParseAssignmentNode(); + var assignmentNode = ParseAssignmentNode(); // 解析复制表达式 NextToken();// 消耗 ";" return assignmentNode; } else { // 以一般语句的形式进行处理,可当作表达式进行解析 - var targetNode = ParserExpression(); // 解析表达式 + var targetNode = ParserExpression(); NextToken();// 消耗 ";" return targetNode; } @@ -176,8 +177,8 @@ namespace Serein.Script /// public ASTNode ParseAssignmentNode() { - /* - 赋值语句: + /* 解析赋值语句 + 赋值语句: 目标对象 表达式获取 Target() | = | Expression() | | = | variable; | (变量) @@ -186,6 +187,7 @@ namespace Serein.Script | = | array[...]; | array为之前的上下文中出现过的变量。 | = | array[...].Value...; | array为之前的上下文中出现过的变量。调用表达式包含对象成员数组、方法 | = | new Class(...); | 实例化类型,包含构造函数 + | = | [v1, v2, v3]; | 定义数组 补充:Target() 可能的成员 1. variable @@ -199,11 +201,12 @@ namespace Serein.Script 如果是 "[" ,代表需要获取数组索引 如果是 "=" ,代表是变量赋值,退出循环 */ - /* - 1. 获取成员 => PeekToken.Type = TokenType.Dot - 2. 获取集合 => PeekToken.Type = TokenType.SquareBracketsLeft - 3. 调用成员方法 => PeekToken.Type = TokenType.ParenthesisLeft - */ + /* 获取成员的方式有三种: + * 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; @@ -211,14 +214,14 @@ namespace Serein.Script List nodes = [targetNode]; ASTNode? source; - var peekToken2 = _lexer.PeekToken(); // 消耗 第一个标识符 - if (JudgmentOperator(peekToken2, "=")) + var peekNextToken = _lexer.PeekToken(); // 预览下个标识符 + if (JudgmentOperator(peekNextToken, "=")) { NextToken(); } else { - if (peekToken2.Type == TokenType.ParenthesisLeft) + if (peekNextToken.Type == TokenType.ParenthesisLeft) { // 解析调用挂载方法 // ... = variable()()(); @@ -230,7 +233,7 @@ namespace Serein.Script } targetNode = functionCallNode; } - else if (peekToken2.Type == TokenType.SquareBracketsLeft) + else if (peekNextToken.Type == TokenType.SquareBracketsLeft) { // 解析集合获取 var collectionIndexNode = ParseCollectionIndexNode(targetNode); @@ -240,7 +243,7 @@ namespace Serein.Script } targetNode = collectionIndexNode; } - else if (peekToken2.Type == TokenType.Dot) + else if (peekNextToken.Type == TokenType.Dot) { NextToken(); } @@ -254,10 +257,11 @@ namespace Serein.Script source = nodes[^1]; // 重定向节点 if (peekToken.Type == TokenType.Dot) // 从对象获取 { - /* - 1. 获取成员 => PeekToken.Type = TokenType.Dot - 2. 获取集合 => PeekToken.Type = TokenType.SquareBracketsLeft - 3. 调用成员方法 => PeekToken.Type = TokenType.ParenthesisLeft + /* + * 获取成员的方式有三种: + * 1. 获取成员 => PeekToken.Type = TokenType.Dot + * 2. 获取集合 => PeekToken.Type = TokenType.SquareBracketsLeft + * 3. 调用成员方法 => PeekToken.Type = TokenType.ParenthesisLeft */ NextToken(); // 消耗 "." 并获取下一个成员。 var peekToken3 = _lexer.PeekToken(); @@ -292,21 +296,7 @@ namespace Serein.Script 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]; @@ -437,14 +427,16 @@ namespace Serein.Script } /// - /// (不处理分号,逗号,右括号)用于解析(...)中的参数部分。终止条件是 "," 参数分隔符 和 ")" 方法入参终止符 + /// (不处理分号,逗号,右括号)用于解析(...) / [...] 中的参数部分。终止条件是 "," 参数分隔符 、")" 方法入参终止符、"]" 数组定义终止符 /// /// public ASTNode ParserArgNode() { ASTNode node = ParserExpression(); // 解析参数 // ParserExpression 会完全解析当前表达式,自动移动到下一个Token,所以需要在这里判断是否符合期望的TokenType - if(_currentToken.Type == TokenType.Comma || _currentToken.Type == TokenType.ParenthesisRight) + if(_currentToken.Type == TokenType.Comma + || _currentToken.Type == TokenType.ParenthesisRight + || _currentToken.Type == TokenType.SquareBracketsRight) { return node; } @@ -1016,6 +1008,24 @@ namespace Serein.Script NextToken(); // 消耗 ")" return expNode; } + else if (_currentToken.Type == TokenType.SquareBracketsLeft) + { + NextToken(); // 消耗 "[" + List elements = []; + while (_currentToken.Type != TokenType.SquareBracketsRight) // 遇到 "]" 时结束 + { + var element = ParserArgNode(); + elements.Add(element); + if (_currentToken.Type == TokenType.Comma) + { + NextToken(); // 消耗参数分隔符 "," + } + } + NextToken(); // 消耗 "]" + + ArrayDefintionNode arrayDefintionNode = new ArrayDefintionNode(elements); + return arrayDefintionNode.SetTokenInfo(_currentToken); + } else if(_currentToken.Type == TokenType.Keyword && _currentToken.Value == "new") // 创建对象 { return ParseObjectInstantiationNode(); diff --git a/Serein.Script/SereinScriptTypeAnalysis.cs b/Serein.Script/SereinScriptTypeAnalysis.cs index 90af454..d07e4f3 100644 --- a/Serein.Script/SereinScriptTypeAnalysis.cs +++ b/Serein.Script/SereinScriptTypeAnalysis.cs @@ -248,6 +248,43 @@ namespace Serein.Script return typeof(void); } return AnalysisCollectionAssignmentNode(collectionAssignmentNode); + case ArrayDefintionNode arrayDefintionNode: + Type AnalysisArrayDefintionNode(ArrayDefintionNode arrayDefintionNode) + { + var elements = arrayDefintionNode.Elements; + if (elements.Count == 0) + { + return typeof(object[]); + } + + Type[] types = new Type[elements.Count]; + for (int i = 0; i < elements.Count; i++) + { + ASTNode? element = elements[i]; + var elementType = Analysis(element); // 分析元素类型 + types[i] = elementType; + NodeSymbolInfos[element] = elementType; // 添加到符号表 + } + + + // 所有类型一致 + if (types.All(t => t == types[0])) + { + var arrType = types[0].MakeArrayType(); + NodeSymbolInfos[arrayDefintionNode] = arrType; // 添加到符号表 + return arrType; + } + else + { + // 尝试找公共基类 + Type? commonType = TypeHelper.FindCommonBaseType(types) ?? typeof(object); + var arrType = commonType.MakeArrayType(); + NodeSymbolInfos[arrayDefintionNode] = arrType; // 添加到符号表 + return arrType; + } + + } + return AnalysisArrayDefintionNode(arrayDefintionNode); case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义 Type AnalysisClassTypeDefinitionNode(ClassTypeDefinitionNode classTypeDefinitionNode) { @@ -412,7 +449,7 @@ namespace Serein.Script default: // 未定义的节点类型 break; } - throw new NotImplementedException(); + throw new NotImplementedException($"类型分析遇到未定义的节点 \"{node.GetType()}\", {node}"); } @@ -422,7 +459,7 @@ namespace Serein.Script /// /// /// - private void Analysis1(ASTNode node) + private void Analysis11111111111(ASTNode node) { switch (node) { diff --git a/Workbench/App.xaml.cs b/Workbench/App.xaml.cs index 56c5835..2e67be7 100644 --- a/Workbench/App.xaml.cs +++ b/Workbench/App.xaml.cs @@ -47,55 +47,8 @@ namespace Serein.Workbench collection.AddViewModelServices(); var services = collection.BuildServiceProvider(); // 绑定并返回获取实例的服务接口 App.ServiceProvider = services; -#if DEBUG - _ = this.LoadLocalProjectAsync(); -#endif } -#if DEBUG - - // 这里是测试代码,可以删除 - private async Task LoadLocalProjectAsync() - { - var script = """ - x = 114514; - x = (x * 100000000000) + x; - value = "调用"; - value = value + "委托"; - return value + x; - """; - var result = await SereinScript.ExecuteAsync(script); - - /* var properties = new Dictionary - { - { "Id", typeof(int) }, - { "Name", typeof(string) }, - { "CreateTime", typeof(DateTime) } - }; - - var type = DynamicObjectHelper.CreateTypeWithINotifyPropertyChanged(properties, "MyDynamicClass"); - dynamic? obj = Activator.CreateInstance(type); - if(obj is null) return; - if (obj is INotifyPropertyChanged npc) - { - npc.PropertyChanged += (s, e) => Debug.WriteLine($"属性改变: {e.PropertyName}"); - } - obj.Name = "下北泽"; - obj.Id = 114514;*/ - - -#if false - var projectService = App.GetService(); - await Task.Delay(500); - string filePath; - filePath = @"F:\TempFile\flow\temp2\project.dnf"; - projectService.LoadLocalProject(filePath); -#endif - - } -#endif - - private void Application_Startup(object sender, StartupEventArgs e) { var projectService = App.GetService(); diff --git a/Workbench/Serein.Workbench.csproj b/Workbench/Serein.Workbench.csproj index 2308c5d..21e22fc 100644 --- a/Workbench/Serein.Workbench.csproj +++ b/Workbench/Serein.Workbench.csproj @@ -32,6 +32,7 @@ +