1. Script项目添加了数组表达式的支持

2. EmitHelper添加了数组创建委托的构建
This commit is contained in:
fengjiayi
2025-07-31 11:21:49 +08:00
parent 85d04029dc
commit 827a9242ae
10 changed files with 254 additions and 105 deletions

View File

@@ -1,10 +1,6 @@
using Serein.Library.Utils; using Serein.Library.Utils;
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using static Serein.Library.Utils.EmitHelper; using static Serein.Library.Utils.EmitHelper;
@@ -54,7 +50,11 @@ namespace Serein.Library
/// <summary> /// <summary>
/// 集合赋值 /// 集合赋值
/// </summary> /// </summary>
CollectionSetter CollectionSetter,
/// <summary>
/// 数组创建
/// </summary>
ArrayCreate,
} }
/// <summary> /// <summary>
@@ -172,6 +172,12 @@ namespace Serein.Library
this.emitType = EmitType.CollectionGetter; this.emitType = EmitType.CollectionGetter;
collectionGetter = EmitHelper.CreateCollectionGetter(type); collectionGetter = EmitHelper.CreateCollectionGetter(type);
} }
else if (emitType == EmitType.ArrayCreate)
{
Func<int, object> func = EmitHelper.CreateArrayFactory(type);
this.arrayCreatefunc = func;
this.emitType = EmitType.ArrayCreate;
}
else else
{ {
throw new NotSupportedException("错误的构建类型"); throw new NotSupportedException("错误的构建类型");
@@ -179,8 +185,8 @@ namespace Serein.Library
} }
private Func<object,object, object> collectionGetter= null; private Func<object,object, object> collectionGetter= null;
@@ -195,6 +201,8 @@ namespace Serein.Library
private Func<object, object[], Task> methodTask = null; private Func<object, object[], Task> methodTask = null;
private Func<object, object[], object> methodInvoke = null; private Func<object, object[], object> methodInvoke = null;
private Func<int, object> arrayCreatefunc = null;
/*/// <summary> /*/// <summary>
/// 更新委托方法 /// 更新委托方法
@@ -260,10 +268,17 @@ namespace Serein.Library
collectionSetter(instance, args[0], args[1]); collectionSetter(instance, args[0], args[1]);
return null; 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<object> MethodInvoke(object instance, object[] args) private async Task<object> MethodInvoke(object instance, object[] args)

View File

@@ -226,10 +226,8 @@ namespace Serein.Library.Utils
}; };
} }
/// <summary> /// <summary>
/// 建字段 Getter 委托Func&lt;object, object&gt; /// 建字段 Getter 委托Func&lt;object, object&gt;
/// </summary> /// </summary>
public static Func<object, object> CreateFieldGetter(FieldInfo fieldInfo) public static Func<object, object> CreateFieldGetter(FieldInfo fieldInfo)
{ {
@@ -271,7 +269,7 @@ namespace Serein.Library.Utils
} }
/// <summary> /// <summary>
/// 建字段 Setter 委托Action&lt;object, object&gt; /// 建字段 Setter 委托Action&lt;object, object&gt;
/// </summary> /// </summary>
public static Action<object, object> CreateFieldSetter(FieldInfo fieldInfo) public static Action<object, object> CreateFieldSetter(FieldInfo fieldInfo)
{ {
@@ -315,7 +313,7 @@ namespace Serein.Library.Utils
} }
/// <summary> /// <summary>
/// 建属性 Getter 委托Func&lt;object, object&gt; /// 建属性 Getter 委托Func&lt;object, object&gt;
/// </summary> /// </summary>
public static Func<object, object> CreatePropertyGetter(PropertyInfo propertyInfo) public static Func<object, object> CreatePropertyGetter(PropertyInfo propertyInfo)
{ {
@@ -357,7 +355,7 @@ namespace Serein.Library.Utils
} }
/// <summary> /// <summary>
/// 建属性 Setter 委托Action&lt;object, object&gt; /// 建属性 Setter 委托Action&lt;object, object&gt;
/// </summary> /// </summary>
public static Action<object, object> CreatePropertySetter(PropertyInfo propertyInfo) public static Action<object, object> CreatePropertySetter(PropertyInfo propertyInfo)
{ {
@@ -402,9 +400,40 @@ namespace Serein.Library.Utils
return (Action<object, object>)method.CreateDelegate(typeof(Action<object, object>)); return (Action<object, object>)method.CreateDelegate(typeof(Action<object, object>));
} }
/// <summary>
/// 构建数组创建委托Func&lt;int, object[]&gt;
/// </summary>
/// <param name="elementType"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static Func<int, object> 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<int, object>)dm.CreateDelegate(typeof(Func<int, object>));
}
/// <summary> /// <summary>
/// 建集合赋值委托Action&lt;object, object, object&gt; /// 建集合赋值委托Action&lt;object, object, object&gt;
/// </summary> /// </summary>
/// <param name="collectionType"></param> /// <param name="collectionType"></param>
/// <returns></returns> /// <returns></returns>
@@ -474,9 +503,8 @@ namespace Serein.Library.Utils
} }
/// <summary> /// <summary>
/// 建集合获取委托Func&lt;object, object, object&gt; /// 建集合获取委托Func&lt;object, object, object&gt;
/// </summary> /// </summary>
/// <param name="collectionType"></param> /// <param name="collectionType"></param>
/// <returns></returns> /// <returns></returns>

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq;
using System.Text; using System.Text;
namespace Serein.Library.Utils namespace Serein.Library.Utils
@@ -173,8 +174,52 @@ namespace Serein.Library.Utils
} }
/// <summary>
/// 发掘类型中的基类
/// </summary>
/// <param name="types"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 查找父类
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
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);
}
} }
} }

View File

@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Script.Node
{
/// <summary>
/// 数组定义节点
/// <para>arr = [1, 2, 3, 4, 5];</para>
/// <para>arr = ["A","B","C"];</para>
/// </summary>
internal class ArrayDefintionNode : ASTNode
{
/// <summary>
/// 数组子项
/// </summary>
public List<ASTNode> Elements { get; } = new List<ASTNode>();
public ArrayDefintionNode(List<ASTNode> elements)
{
Elements = elements;
}
}
}

View File

@@ -175,6 +175,39 @@ namespace Serein.Script
return result; return result;
} }
return await InterpreterCollectionIndexNodeAsync(context, collectionIndexNode); return await InterpreterCollectionIndexNodeAsync(context, collectionIndexNode);
case ArrayDefintionNode arrayDefintionNode:
async Task<Array> InterpreterArrayDefintionNodeAsync(ArrayDefintionNode arrayDefintionNode)
{
var elementNodes = arrayDefintionNode.Elements;
var elementCount = elementNodes.Count;
if(elementCount == 0)
{
return Array.Empty<object>();
}
/*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: // 类型定义 case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义
void InterpreterClassTypeDefinitionNode(IScriptInvokeContext context, ClassTypeDefinitionNode classTypeDefinitionNode) void InterpreterClassTypeDefinitionNode(IScriptInvokeContext context, ClassTypeDefinitionNode classTypeDefinitionNode)
{ {

View File

@@ -123,7 +123,7 @@
public override string ToString() 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}\"";
} }
} }

View File

@@ -117,18 +117,19 @@ namespace Serein.Script
} }
} }
#endregion #endregion
#region ASTNode
#region /ASTNode
if (isAssignment) if (isAssignment)
{ {
// 以赋值语句的形式进行处理 // 以赋值语句的形式进行处理
var assignmentNode = ParseAssignmentNode(); var assignmentNode = ParseAssignmentNode(); // 解析复制表达式
NextToken();// 消耗 ";" NextToken();// 消耗 ";"
return assignmentNode; return assignmentNode;
} }
else else
{ {
// 以一般语句的形式进行处理,可当作表达式进行解析 // 以一般语句的形式进行处理,可当作表达式进行解析
var targetNode = ParserExpression(); // 解析表达式 var targetNode = ParserExpression();
NextToken();// 消耗 ";" NextToken();// 消耗 ";"
return targetNode; return targetNode;
} }
@@ -176,8 +177,8 @@ namespace Serein.Script
/// <returns></returns> /// <returns></returns>
public ASTNode ParseAssignmentNode() public ASTNode ParseAssignmentNode()
{ {
/* /* 解析赋值语句
赋值语句: 赋值语句:
目标对象 表达式获取 目标对象 表达式获取
Target() | = | Expression() | Target() | = | Expression() |
| = | variable; | (变量) | = | variable; | (变量)
@@ -186,6 +187,7 @@ namespace Serein.Script
| = | array[...]; | array为之前的上下文中出现过的变量。 | = | array[...]; | array为之前的上下文中出现过的变量。
| = | array[...].Value...; | array为之前的上下文中出现过的变量。调用表达式包含对象成员数组、方法 | = | array[...].Value...; | array为之前的上下文中出现过的变量。调用表达式包含对象成员数组、方法
| = | new Class(...); | 实例化类型,包含构造函数 | = | new Class(...); | 实例化类型,包含构造函数
| = | [v1, v2, v3]; | 定义数组
补充Target() 可能的成员 补充Target() 可能的成员
1. variable 1. variable
@@ -199,11 +201,12 @@ namespace Serein.Script
如果是 "[" ,代表需要获取数组索引 如果是 "[" ,代表需要获取数组索引
如果是 "=" ,代表是变量赋值,退出循环 如果是 "=" ,代表是变量赋值,退出循环
*/ */
/* /* 获取成员的方式有三种:
1. 获取成员 => PeekToken.Type = TokenType.Dot * 1. 获取成员 => PeekToken.Type = TokenType.Dot
2. 获取集合 => PeekToken.Type = TokenType.SquareBracketsLeft * 2. 获取集合 => PeekToken.Type = TokenType.SquareBracketsLeft
3. 调用成员方法 => PeekToken.Type = TokenType.ParenthesisLeft * 3. 调用成员方法 => PeekToken.Type = TokenType.ParenthesisLeft
*/ *
* */
//if (JudgmentOperator(_currentToken, "=")) break; // 退出 //if (JudgmentOperator(_currentToken, "=")) break; // 退出
//var tempPeekToken = _lexer.PeekToken(); //var tempPeekToken = _lexer.PeekToken();
var backupToken = _currentToken; var backupToken = _currentToken;
@@ -211,14 +214,14 @@ namespace Serein.Script
List<ASTNode> nodes = [targetNode]; List<ASTNode> nodes = [targetNode];
ASTNode? source; ASTNode? source;
var peekToken2 = _lexer.PeekToken(); // 消耗 第一个标识符 var peekNextToken = _lexer.PeekToken(); // 预览下个标识符
if (JudgmentOperator(peekToken2, "=")) if (JudgmentOperator(peekNextToken, "="))
{ {
NextToken(); NextToken();
} }
else else
{ {
if (peekToken2.Type == TokenType.ParenthesisLeft) if (peekNextToken.Type == TokenType.ParenthesisLeft)
{ {
// 解析调用挂载方法 // 解析调用挂载方法
// ... = variable()()(); // ... = variable()()();
@@ -230,7 +233,7 @@ namespace Serein.Script
} }
targetNode = functionCallNode; targetNode = functionCallNode;
} }
else if (peekToken2.Type == TokenType.SquareBracketsLeft) else if (peekNextToken.Type == TokenType.SquareBracketsLeft)
{ {
// 解析集合获取 // 解析集合获取
var collectionIndexNode = ParseCollectionIndexNode(targetNode); var collectionIndexNode = ParseCollectionIndexNode(targetNode);
@@ -240,7 +243,7 @@ namespace Serein.Script
} }
targetNode = collectionIndexNode; targetNode = collectionIndexNode;
} }
else if (peekToken2.Type == TokenType.Dot) else if (peekNextToken.Type == TokenType.Dot)
{ {
NextToken(); NextToken();
} }
@@ -254,10 +257,11 @@ namespace Serein.Script
source = nodes[^1]; // 重定向节点 source = nodes[^1]; // 重定向节点
if (peekToken.Type == TokenType.Dot) // 从对象获取 if (peekToken.Type == TokenType.Dot) // 从对象获取
{ {
/* /*
1. 获取成员 => PeekToken.Type = TokenType.Dot * 获取成员的方式有三种:
2. 获取集合 => PeekToken.Type = TokenType.SquareBracketsLeft * 1. 获取成员 => PeekToken.Type = TokenType.Dot
3. 调用成员方法 => PeekToken.Type = TokenType.ParenthesisLeft * 2. 获取集合 => PeekToken.Type = TokenType.SquareBracketsLeft
* 3. 调用成员方法 => PeekToken.Type = TokenType.ParenthesisLeft
*/ */
NextToken(); // 消耗 "." 并获取下一个成员。 NextToken(); // 消耗 "." 并获取下一个成员。
var peekToken3 = _lexer.PeekToken(); var peekToken3 = _lexer.PeekToken();
@@ -292,21 +296,7 @@ namespace Serein.Script
nodes.Add(collectionIndexNode); nodes.Add(collectionIndexNode);
continue; // 结束当前轮次的token判断 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]; targetNode = nodes[^1];
@@ -437,14 +427,16 @@ namespace Serein.Script
} }
/// <summary> /// <summary>
/// (不处理分号,逗号,右括号)用于解析(...)中的参数部分。终止条件是 "," 参数分隔符 ")" 方法入参终止符 /// (不处理分号,逗号,右括号)用于解析(...) / [...] 中的参数部分。终止条件是 "," 参数分隔符 ")" 方法入参终止符、"]" 数组定义终止符
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public ASTNode ParserArgNode() public ASTNode ParserArgNode()
{ {
ASTNode node = ParserExpression(); // 解析参数 ASTNode node = ParserExpression(); // 解析参数
// ParserExpression 会完全解析当前表达式自动移动到下一个Token所以需要在这里判断是否符合期望的TokenType // 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; return node;
} }
@@ -1016,6 +1008,24 @@ namespace Serein.Script
NextToken(); // 消耗 ")" NextToken(); // 消耗 ")"
return expNode; return expNode;
} }
else if (_currentToken.Type == TokenType.SquareBracketsLeft)
{
NextToken(); // 消耗 "["
List<ASTNode> 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") // 创建对象 else if(_currentToken.Type == TokenType.Keyword && _currentToken.Value == "new") // 创建对象
{ {
return ParseObjectInstantiationNode(); return ParseObjectInstantiationNode();

View File

@@ -248,6 +248,43 @@ namespace Serein.Script
return typeof(void); return typeof(void);
} }
return AnalysisCollectionAssignmentNode(collectionAssignmentNode); 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: // 类型定义 case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义
Type AnalysisClassTypeDefinitionNode(ClassTypeDefinitionNode classTypeDefinitionNode) Type AnalysisClassTypeDefinitionNode(ClassTypeDefinitionNode classTypeDefinitionNode)
{ {
@@ -412,7 +449,7 @@ namespace Serein.Script
default: // 未定义的节点类型 default: // 未定义的节点类型
break; break;
} }
throw new NotImplementedException(); throw new NotImplementedException($"类型分析遇到未定义的节点 \"{node.GetType()}\", {node}");
} }
@@ -422,7 +459,7 @@ namespace Serein.Script
/// </summary> /// </summary>
/// <param name="node"></param> /// <param name="node"></param>
/// <exception cref="NotImplementedException"></exception> /// <exception cref="NotImplementedException"></exception>
private void Analysis1(ASTNode node) private void Analysis11111111111(ASTNode node)
{ {
switch (node) switch (node)
{ {

View File

@@ -47,55 +47,8 @@ namespace Serein.Workbench
collection.AddViewModelServices(); collection.AddViewModelServices();
var services = collection.BuildServiceProvider(); // 绑定并返回获取实例的服务接口 var services = collection.BuildServiceProvider(); // 绑定并返回获取实例的服务接口
App.ServiceProvider = services; 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<string, Type>
{
{ "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<FlowProjectService>();
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) private void Application_Startup(object sender, StartupEventArgs e)
{ {
var projectService = App.GetService<FlowProjectService>(); var projectService = App.GetService<FlowProjectService>();

View File

@@ -32,6 +32,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Remove="Converters\TypeToColorConverter.cs" />
<Compile Remove="MainWindow.xaml.cs" /> <Compile Remove="MainWindow.xaml.cs" />
<Compile Remove="MainWindowViewModel.cs" /> <Compile Remove="MainWindowViewModel.cs" />
<Compile Remove="Node\FlipflopRegionControl.xaml.cs" /> <Compile Remove="Node\FlipflopRegionControl.xaml.cs" />