mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-03 00:00:49 +08:00
修复了脚本语言中构造器赋值的 bug
This commit is contained in:
@@ -5,6 +5,7 @@ using System.Reflection.Emit;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Serein.Library.Utils
|
||||
{
|
||||
@@ -188,8 +189,142 @@ namespace Serein.Library.Utils
|
||||
return dynamicType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建继承通知接口、具有属性的类型
|
||||
/// </summary>
|
||||
/// <param name="properties"></param>
|
||||
/// <param name="typeName"></param>
|
||||
/// <param name="isOverlay"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public static Type CreateTypeWithINotifyPropertyChanged(IDictionary<string, Type> properties, string typeName, bool isOverlay = false)
|
||||
{
|
||||
if (typeCache.ContainsKey(typeName) && !isOverlay)
|
||||
return typeCache[typeName];
|
||||
|
||||
var typeBuilder = ModuleBuilder.DefineType(typeName, TypeAttributes.Public | TypeAttributes.Class);
|
||||
typeBuilder.AddInterfaceImplementation(typeof(INotifyPropertyChanged));
|
||||
|
||||
// 添加 PropertyChanged 字段
|
||||
var eventHandlerType = typeof(PropertyChangedEventHandler);
|
||||
var propertyChangedField = typeBuilder.DefineField("PropertyChanged", eventHandlerType, FieldAttributes.Private);
|
||||
|
||||
// 添加 PropertyChanged 事件
|
||||
var eventBuilder = typeBuilder.DefineEvent("PropertyChanged", EventAttributes.None, eventHandlerType);
|
||||
|
||||
// add_PropertyChanged
|
||||
var addMethod = typeBuilder.DefineMethod("add_PropertyChanged", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Virtual | MethodAttributes.HideBySig, null, new[] { eventHandlerType });
|
||||
{
|
||||
|
||||
var il = addMethod.GetILGenerator();
|
||||
var combine = typeof(Delegate).GetMethod("Combine", new[] { typeof(Delegate), typeof(Delegate) });
|
||||
|
||||
// this.PropertyChanged = (PropertyChangedEventHandler)Delegate.Combine(this.PropertyChanged, value);
|
||||
il.Emit(OpCodes.Ldarg_0); // 加载 this(当前实例)到栈
|
||||
il.Emit(OpCodes.Ldarg_0); // 再次加载 this,用于访问字段
|
||||
il.Emit(OpCodes.Ldfld, propertyChangedField); // 加载 this.PropertyChanged 字段值
|
||||
il.Emit(OpCodes.Ldarg_1); // 加载方法参数 value(订阅者委托)
|
||||
il.Emit(OpCodes.Call, combine); // 调用 Delegate.Combine(a, b)
|
||||
il.Emit(OpCodes.Castclass, eventHandlerType); // 强转回 PropertyChangedEventHandler 类型
|
||||
il.Emit(OpCodes.Stfld, propertyChangedField); // 赋值给 this.PropertyChanged
|
||||
il.Emit(OpCodes.Ret); // return
|
||||
}
|
||||
|
||||
// remove_PropertyChanged
|
||||
var removeMethod = typeBuilder.DefineMethod("remove_PropertyChanged", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.Virtual | MethodAttributes.HideBySig, null, new[] { eventHandlerType });
|
||||
{
|
||||
var il = removeMethod.GetILGenerator();
|
||||
var remove = typeof(Delegate).GetMethod("Remove", new[] { typeof(Delegate), typeof(Delegate) });
|
||||
|
||||
// this.PropertyChanged = (PropertyChangedEventHandler)Delegate.Remove(this.PropertyChanged, value);
|
||||
il.Emit(OpCodes.Ldarg_0); // 加载 this
|
||||
il.Emit(OpCodes.Ldarg_0); // 再次加载 this
|
||||
il.Emit(OpCodes.Ldfld, propertyChangedField); // 加载字段 this.PropertyChanged
|
||||
il.Emit(OpCodes.Ldarg_1); // 加载 value(要移除的委托)
|
||||
il.Emit(OpCodes.Call, remove); // 调用 Delegate.Remove(a, b)
|
||||
il.Emit(OpCodes.Castclass, eventHandlerType); // 转换为 PropertyChangedEventHandler
|
||||
il.Emit(OpCodes.Stfld, propertyChangedField); // 设置 this.PropertyChanged = 结果
|
||||
il.Emit(OpCodes.Ret); // return
|
||||
}
|
||||
|
||||
eventBuilder.SetAddOnMethod(addMethod);
|
||||
eventBuilder.SetRemoveOnMethod(removeMethod);
|
||||
|
||||
// 定义 OnPropertyChanged 方法
|
||||
var onPropertyChangedMethod = typeBuilder.DefineMethod(
|
||||
"OnPropertyChanged",
|
||||
MethodAttributes.Private,
|
||||
null,
|
||||
new[] { typeof(string) });
|
||||
|
||||
{
|
||||
var il = onPropertyChangedMethod.GetILGenerator();
|
||||
var label = il.DefineLabel();
|
||||
|
||||
// if (PropertyChanged == null) return;
|
||||
il.Emit(OpCodes.Ldarg_0); // 加载 this
|
||||
il.Emit(OpCodes.Ldfld, propertyChangedField); // 加载 this.PropertyChanged
|
||||
il.Emit(OpCodes.Brfalse_S, label); // 如果为空(null),跳转到 label,跳过通知调用
|
||||
|
||||
// PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
il.Emit(OpCodes.Ldarg_0); // 加载 this(委托调用目标)
|
||||
il.Emit(OpCodes.Ldfld, propertyChangedField); // 加载 PropertyChanged 委托
|
||||
il.Emit(OpCodes.Ldarg_0); // 加载 this 作为 sender 参数
|
||||
il.Emit(OpCodes.Ldarg_1); // 加载 propertyName 参数(string)
|
||||
il.Emit(OpCodes.Newobj, typeof(PropertyChangedEventArgs).GetConstructor(new[] { typeof(string) })); // 构造 new PropertyChangedEventArgs(propertyName)
|
||||
il.Emit(OpCodes.Callvirt, typeof(PropertyChangedEventHandler).GetMethod("Invoke")); // 调用委托 Invoke(sender, args)
|
||||
il.MarkLabel(label); // 跳转目标(如果委托为 null 则跳转至此)
|
||||
il.Emit(OpCodes.Ret); // return
|
||||
}
|
||||
|
||||
// 为每个属性生成字段 + get/set + OnPropertyChanged 调用
|
||||
foreach (var kv in properties)
|
||||
{
|
||||
string propName = kv.Key;
|
||||
Type propType = kv.Value ?? typeof(object);
|
||||
|
||||
var fieldBuilder = typeBuilder.DefineField("_" + propName, propType, FieldAttributes.Private);
|
||||
|
||||
var propertyBuilder = typeBuilder.DefineProperty(propName, PropertyAttributes.HasDefault, propType, null);
|
||||
|
||||
var getter = typeBuilder.DefineMethod("get_" + propName,
|
||||
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
|
||||
propType, Type.EmptyTypes);
|
||||
|
||||
{
|
||||
// get_PropertyName()
|
||||
var il = getter.GetILGenerator();
|
||||
il.Emit(OpCodes.Ldarg_0); // 加载 this
|
||||
il.Emit(OpCodes.Ldfld, fieldBuilder); // 读取私有字段 _PropertyName
|
||||
il.Emit(OpCodes.Ret); // 返回字段值
|
||||
}
|
||||
|
||||
var setter = typeBuilder.DefineMethod("set_" + propName,
|
||||
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
|
||||
null, new[] { propType });
|
||||
|
||||
{
|
||||
// set_PropertyName(value)
|
||||
var il = setter.GetILGenerator();
|
||||
il.Emit(OpCodes.Ldarg_0); // 加载 this
|
||||
il.Emit(OpCodes.Ldarg_1); // 加载 value 参数
|
||||
il.Emit(OpCodes.Stfld, fieldBuilder); // 设置字段 _PropertyName = value
|
||||
|
||||
il.Emit(OpCodes.Ldarg_0); // 加载 this
|
||||
il.Emit(OpCodes.Ldstr, propName); // 加载属性名字符串作为通知参数
|
||||
il.Emit(OpCodes.Call, onPropertyChangedMethod); // 调用 OnPropertyChanged(propName)
|
||||
|
||||
il.Emit(OpCodes.Ret); // return
|
||||
}
|
||||
|
||||
propertyBuilder.SetGetMethod(getter);
|
||||
propertyBuilder.SetSetMethod(setter);
|
||||
}
|
||||
|
||||
var dynamicType = typeBuilder.CreateType();
|
||||
typeCache[typeName] = dynamicType;
|
||||
return dynamicType;
|
||||
}
|
||||
#region 动态创建对象并赋值
|
||||
|
||||
// 方法 1: 创建动态类型及其对象实例
|
||||
|
||||
@@ -33,19 +33,20 @@ namespace Serein.NodeFlow.Model
|
||||
/// </summary>
|
||||
public override bool IsBase => true;
|
||||
|
||||
private IScriptFlowApi ScriptFlowApi;
|
||||
private ProgramNode programNode;
|
||||
private readonly SereinScriptInterpreter scriptInterpreter;
|
||||
private bool IsScriptChanged = false;
|
||||
|
||||
/// <summary>
|
||||
/// 脚本解释器
|
||||
/// </summary>
|
||||
private readonly SereinScript sereinScript;
|
||||
|
||||
/// <summary>
|
||||
/// 构建流程脚本节点
|
||||
/// </summary>
|
||||
/// <param name="environment"></param>
|
||||
public SingleScriptNode(IFlowEnvironment environment):base(environment)
|
||||
public SingleScriptNode(IFlowEnvironment environment) : base(environment)
|
||||
{
|
||||
ScriptFlowApi = new ScriptFlowApi(environment, this);
|
||||
scriptInterpreter = new SereinScriptInterpreter();
|
||||
sereinScript = new SereinScript();
|
||||
}
|
||||
|
||||
static SingleScriptNode()
|
||||
@@ -60,7 +61,7 @@ namespace Serein.NodeFlow.Model
|
||||
// 加载基础方法
|
||||
foreach ((string name, MethodInfo method) item in tempMethods)
|
||||
{
|
||||
SereinScriptInterpreter.AddStaticFunction(item.name, item.method);
|
||||
SereinScript.AddStaticFunction(item.name, item.method);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,24 +158,10 @@ namespace Serein.NodeFlow.Model
|
||||
varNames.Add(pd.Name);
|
||||
}
|
||||
|
||||
/*var sb = new StringBuilder();
|
||||
foreach (var pd in MethodDetails.ParameterDetailss)
|
||||
{
|
||||
sb.AppendLine($"let {pd.Name};"); // 提前声明这些变量
|
||||
}
|
||||
sb.Append(Script);
|
||||
var script = sb.ToString();*/
|
||||
var parser = new SereinScriptParser(); // 准备解析器
|
||||
var typeAnalysis = new SereinScriptTypeAnalysis(); // 准备分析器
|
||||
programNode = parser.Parse(Script); // 开始解析获取程序主节点
|
||||
Dictionary<string, Type> dict = MethodDetails.ParameterDetailss.ToDictionary(pd => pd.Name, pd => pd.DataType); // 准备预定义类型
|
||||
|
||||
var dict = MethodDetails.ParameterDetailss.ToDictionary(pd => pd.Name, pd => pd.DataType);
|
||||
typeAnalysis.NodeSymbolInfos.Clear(); // 清空符号表
|
||||
typeAnalysis.LoadSymbol(dict); // 提前加载脚本节点定义的符号
|
||||
typeAnalysis.AnalysisProgramNode(programNode); // 分析节点类型
|
||||
var returnType = typeAnalysis.NodeSymbolInfos[programNode]; // 获取返回类型
|
||||
var returnType = sereinScript.ParserScript(dict, Script); // 开始解析获取程序主节点
|
||||
MethodDetails.ReturnType = returnType;
|
||||
//scriptInterpreter.SetTypeAnalysis(typeAnalysis); // 设置类型分析器
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -244,8 +231,7 @@ namespace Serein.NodeFlow.Model
|
||||
|
||||
if (token.IsCancellationRequested) return null;
|
||||
|
||||
|
||||
var result = await scriptInterpreter.InterpretAsync(scriptContext, programNode); // 从入口节点执行
|
||||
var result = await sereinScript.InterpreterAsync(scriptContext); // 从入口节点执行
|
||||
envEvent.FlowRunComplete -= onFlowStop;
|
||||
return new FlowResult(this.Guid, context, result);
|
||||
}
|
||||
@@ -259,12 +245,7 @@ namespace Serein.NodeFlow.Model
|
||||
|
||||
private static class ScriptBaseFunc
|
||||
{
|
||||
public static DateTime GetNow() => DateTime.Now;
|
||||
|
||||
public static int Add(int Left, int Right)
|
||||
{
|
||||
return Left + Right;
|
||||
}
|
||||
public static DateTime now() => DateTime.Now;
|
||||
|
||||
#region 常用的类型转换
|
||||
public static bool @bool(object value)
|
||||
@@ -321,6 +302,21 @@ namespace Serein.NodeFlow.Model
|
||||
}
|
||||
}
|
||||
|
||||
public static void regType(Type type, string name = "")
|
||||
{
|
||||
SereinScript.AddClassType(type, name);
|
||||
}
|
||||
|
||||
public static string str(object obj)
|
||||
{
|
||||
return obj?.ToString() ?? string.Empty;
|
||||
}
|
||||
|
||||
public static object obj(Type type)
|
||||
{
|
||||
return Activator.CreateInstance(type);
|
||||
}
|
||||
|
||||
public static Type type(object type)
|
||||
{
|
||||
return type.GetType();
|
||||
|
||||
@@ -15,41 +15,40 @@ namespace Serein.Script.Node
|
||||
public bool IsOverlay { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 类名称
|
||||
/// 类型名称
|
||||
/// </summary>
|
||||
public string ClassName { get; }
|
||||
public TypeNode ClassType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 字段名称及字段类型
|
||||
/// 类型中的属性
|
||||
/// </summary>
|
||||
[Obsolete("此属性已经过时,将会改为Dictionary<string, string>", false)]
|
||||
public Dictionary<string, Type> Fields { get; }
|
||||
public Dictionary<string, TypeNode> Propertys { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 字段名称及字段类型(Kvp[fididName:fidleTypeName])
|
||||
/// </summary>
|
||||
public Dictionary<string, string> FieldInfos { get; }
|
||||
|
||||
public ClassTypeDefinitionNode(Dictionary<string, string> fields, string className)
|
||||
public ClassTypeDefinitionNode(Dictionary<string, TypeNode> propertys, TypeNode className)
|
||||
{
|
||||
this.FieldInfos = fields;
|
||||
this.ClassName = className;
|
||||
this.Propertys = propertys;
|
||||
this.ClassType = className;
|
||||
}
|
||||
|
||||
[Obsolete("此构造方法已经过时,可能在下一个版本中移除", false)]
|
||||
public ClassTypeDefinitionNode(Dictionary<string, Type> fields, string className)
|
||||
{
|
||||
this.Fields = fields;
|
||||
this.ClassName = className;
|
||||
}
|
||||
|
||||
[Obsolete("此构造方法已经过时,可能在下一个版本中移除", false)]
|
||||
public ClassTypeDefinitionNode(Dictionary<string, Type> fields, string className, bool isOverlay)
|
||||
{
|
||||
this.Fields = fields;
|
||||
this.ClassName = className;
|
||||
IsOverlay = isOverlay;
|
||||
}
|
||||
|
||||
|
||||
/* /// <summary>
|
||||
/// 字段名称及字段类型
|
||||
/// </summary>
|
||||
[Obsolete("此属性已经过时,将会改为Dictionary<string, string>", false)]
|
||||
public Dictionary<TypeNode, Type> Fields { get; }
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/* /// <summary>
|
||||
/// 字段名称及字段类型(Kvp[fididName:fidleTypeName])
|
||||
/// </summary>
|
||||
public Dictionary<TypeNode, string> FieldInfos { get; }
|
||||
*/
|
||||
//[Obsolete("此构造方法已经过时,可能在下一个版本中移除", false)]
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
46
Serein.Script/Node/CtorAssignmentNode.cs
Normal file
46
Serein.Script/Node/CtorAssignmentNode.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Script.Node
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 构造器对对象成员赋值
|
||||
/// </summary>
|
||||
public class CtorAssignmentNode : ASTNode
|
||||
{
|
||||
/// <summary>
|
||||
/// 成员来源类型
|
||||
/// </summary>
|
||||
public TypeNode Class { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 成员名称
|
||||
/// </summary>
|
||||
public string MemberName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 值来源
|
||||
/// </summary>
|
||||
public ASTNode Value { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 构造器赋值
|
||||
/// </summary>
|
||||
/// <param name="typeNode">成员来源类型</param>
|
||||
/// <param name="memberName">成员名称</param>
|
||||
/// <param name="value">成员值来源</param>
|
||||
public CtorAssignmentNode(TypeNode typeNode, string memberName, ASTNode value)
|
||||
{
|
||||
Class = typeNode;
|
||||
MemberName = memberName;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -12,19 +12,31 @@ namespace Serein.Script.Node
|
||||
public class ObjectInstantiationNode : ASTNode
|
||||
{
|
||||
/// <summary>
|
||||
/// 类型名称
|
||||
/// 类型来源
|
||||
/// </summary>
|
||||
public string TypeName { get; }
|
||||
public TypeNode Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 构造方法的参数来源
|
||||
/// </summary>
|
||||
public List<ASTNode> Arguments { get; }
|
||||
public ObjectInstantiationNode(string typeName, List<ASTNode> arguments)
|
||||
|
||||
/// <summary>
|
||||
/// 构造器赋值
|
||||
/// </summary>
|
||||
public List<CtorAssignmentNode> CtorAssignments { get; private set; } = [];
|
||||
|
||||
public ObjectInstantiationNode(TypeNode type, List<ASTNode> arguments)
|
||||
{
|
||||
this.TypeName = typeName;
|
||||
this.Type = type;
|
||||
this.Arguments = arguments;
|
||||
}
|
||||
|
||||
public ObjectInstantiationNode SetCtorAssignments(List<CtorAssignmentNode> ctorAssignments)
|
||||
{
|
||||
CtorAssignments = ctorAssignments;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
22
Serein.Script/Node/TypeNode.cs
Normal file
22
Serein.Script/Node/TypeNode.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Script.Node
|
||||
{
|
||||
/// <summary>
|
||||
/// 类型节点
|
||||
/// </summary>
|
||||
public class TypeNode : ASTNode
|
||||
{
|
||||
public string TypeName { get; }
|
||||
|
||||
public TypeNode(string typeName)
|
||||
{
|
||||
TypeName = typeName;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
131
Serein.Script/SereinScript.cs
Normal file
131
Serein.Script/SereinScript.cs
Normal file
@@ -0,0 +1,131 @@
|
||||
using Serein.Library;
|
||||
using Serein.Script.Node;
|
||||
using Serein.Script.Node.FlowControl;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Script
|
||||
{
|
||||
public class SereinScript
|
||||
{
|
||||
/// <summary>
|
||||
/// 类型分析
|
||||
/// </summary>
|
||||
public SereinScriptTypeAnalysis TypeAnalysis { get; set; } = new SereinScriptTypeAnalysis();
|
||||
|
||||
|
||||
|
||||
private ProgramNode? programNode;
|
||||
|
||||
public Type ParserScript(Dictionary<string, Type> argTypes, string script)
|
||||
{
|
||||
SereinScriptParser parser = new SereinScriptParser();
|
||||
var programNode = parser.Parse(script);
|
||||
TypeAnalysis.NodeSymbolInfos.Clear(); // 清空符号表
|
||||
TypeAnalysis.LoadSymbol(argTypes); // 提前加载脚本节点定义的符号
|
||||
TypeAnalysis.Analysis(programNode); // 分析节点类型
|
||||
var returnType = TypeAnalysis.NodeSymbolInfos[programNode]; // 获取返回类型
|
||||
this.programNode = programNode;
|
||||
return returnType; // 脚本返回类型
|
||||
}
|
||||
|
||||
public async Task<object?> InterpreterAsync(IScriptInvokeContext context)
|
||||
{
|
||||
if(programNode is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(programNode));
|
||||
}
|
||||
Dictionary<ASTNode, Type> symbolInfos = TypeAnalysis.NodeSymbolInfos.ToDictionary();
|
||||
SereinScriptInterpreter Interpreter = new SereinScriptInterpreter(symbolInfos);
|
||||
return await Interpreter.InterpretAsync(context, programNode);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 挂载的函数
|
||||
/// </summary>
|
||||
public static Dictionary<string, DelegateDetails> FunctionDelegates { get; private set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// 挂载方法的信息
|
||||
/// </summary>
|
||||
public static Dictionary<string, MethodInfo> FunctionInfos { get; private set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// 挂载的类型
|
||||
/// </summary>
|
||||
public static Dictionary<string, Type> MountType = new Dictionary<string, Type>();
|
||||
|
||||
/// <summary>
|
||||
/// 挂载的函数调用的对象(用于解决函数需要实例才能调用的场景)
|
||||
/// </summary>
|
||||
public static Dictionary<string, Func<object>> DelegateInstances = new Dictionary<string, Func<object>>();
|
||||
|
||||
/// <summary>
|
||||
/// 挂载静态函数
|
||||
/// </summary>
|
||||
/// <param name="functionName"></param>
|
||||
/// <param name="methodInfo"></param>
|
||||
public static void AddStaticFunction(string functionName, MethodInfo methodInfo)
|
||||
{
|
||||
FunctionDelegates[functionName] = new DelegateDetails(methodInfo);
|
||||
FunctionInfos[functionName] = methodInfo;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 挂载函数
|
||||
/// </summary>
|
||||
/// <param name="functionName">函数名称</param>
|
||||
/// <param name="methodInfo">方法信息</param>
|
||||
public static void AddFunction(string functionName, MethodInfo methodInfo, Func<object>? callObj = null)
|
||||
{
|
||||
if (!methodInfo.IsStatic && callObj is null)
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.WARN, "函数挂载失败:试图挂载非静态的函数,但没有传入相应的获取实例的方法。");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!methodInfo.IsStatic && callObj is not null && !DelegateInstances.ContainsKey(functionName))
|
||||
{
|
||||
// 非静态函数需要给定类型
|
||||
DelegateInstances.Add(functionName, callObj);
|
||||
}
|
||||
if (!FunctionDelegates.ContainsKey(functionName))
|
||||
{
|
||||
FunctionDelegates[functionName] = new DelegateDetails(methodInfo);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 挂载类型
|
||||
/// </summary>
|
||||
/// <param name="typeName">函数名称</param>
|
||||
/// <param name="typeName">指定类型名称</param>
|
||||
public static void AddClassType(Type type, string typeName = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(typeName))
|
||||
{
|
||||
typeName = type.Name;
|
||||
}
|
||||
if (!MountType.ContainsKey(typeName))
|
||||
{
|
||||
MountType[typeName] = type;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -18,99 +18,16 @@ namespace Serein.Script
|
||||
/// </summary>
|
||||
public class SereinScriptInterpreter
|
||||
{
|
||||
private readonly Dictionary<ASTNode, Type> symbolInfos;
|
||||
|
||||
/// <summary>
|
||||
/// 挂载的函数
|
||||
/// </summary>
|
||||
private static Dictionary<string, DelegateDetails> _functionTable = new Dictionary<string, DelegateDetails>();
|
||||
private static Dictionary<string, MethodInfo> _functionInfoTable = new Dictionary<string, MethodInfo>();
|
||||
|
||||
public static Dictionary<string, MethodInfo> FunctionInfoTable { get { return _functionInfoTable; } }
|
||||
|
||||
/// <summary>
|
||||
/// 挂载的函数调用的对象(用于函数需要实例才能调用的场景)
|
||||
/// </summary>
|
||||
private Dictionary<string, Func<object>> _callFuncOfGetObjects = new Dictionary<string, Func<object>>();
|
||||
|
||||
/// <summary>
|
||||
/// 定义的类型
|
||||
/// </summary>
|
||||
private Dictionary<string, Type> _classDefinition = new Dictionary<string, Type>();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 类型分析器
|
||||
/// </summary>
|
||||
private SereinScriptTypeAnalysis typeAnalysis;
|
||||
|
||||
/// <summary>
|
||||
/// 挂载静态函数
|
||||
/// </summary>
|
||||
/// <param name="functionName"></param>
|
||||
/// <param name="methodInfo"></param>
|
||||
public static void AddStaticFunction(string functionName, MethodInfo methodInfo)
|
||||
public SereinScriptInterpreter(Dictionary<ASTNode, Type> symbolInfos)
|
||||
{
|
||||
_functionTable[functionName] = new DelegateDetails(methodInfo);
|
||||
_functionInfoTable[functionName] = methodInfo;
|
||||
this.symbolInfos = symbolInfos;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 挂载函数
|
||||
/// </summary>
|
||||
/// <param name="functionName">函数名称</param>
|
||||
/// <param name="methodInfo">方法信息</param>
|
||||
public void AddFunction(string functionName, MethodInfo methodInfo, Func<object>? callObj = null)
|
||||
{
|
||||
//if (!_functionTable.ContainsKey(functionName))
|
||||
//{
|
||||
// _functionTable[functionName] = new DelegateDetails(methodInfo);
|
||||
//}
|
||||
if(!methodInfo.IsStatic && callObj is null)
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.WARN, "函数挂载失败:试图挂载非静态的函数,但没有传入相应的获取实例的方法。");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if(!methodInfo.IsStatic && callObj is not null && !_callFuncOfGetObjects.ContainsKey(functionName))
|
||||
{
|
||||
// 静态函数不需要
|
||||
_callFuncOfGetObjects.Add(functionName, callObj);
|
||||
}
|
||||
if (!_functionTable.ContainsKey(functionName))
|
||||
{
|
||||
_functionTable[functionName] = new DelegateDetails(methodInfo);
|
||||
}
|
||||
//_functionTable[functionName] = new DelegateDetails(methodInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 挂载类型
|
||||
/// </summary>
|
||||
/// <param name="typeName">函数名称</param>
|
||||
/// <param name="type">方法信息</param>
|
||||
public void AddClassType(Type type , string typeName = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(typeName))
|
||||
{
|
||||
typeName = type.Name;
|
||||
}
|
||||
if (!_classDefinition.ContainsKey(typeName))
|
||||
{
|
||||
_classDefinition[typeName] = type;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置类型分析器
|
||||
/// </summary>
|
||||
/// <param name="typeAnalysis"></param>
|
||||
public void SetTypeAnalysis(SereinScriptTypeAnalysis typeAnalysis)
|
||||
{
|
||||
this.typeAnalysis = typeAnalysis;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 入口节点
|
||||
/// </summary>
|
||||
@@ -159,17 +76,19 @@ namespace Serein.Script
|
||||
/// <returns></returns>
|
||||
private void ExecutionClassTypeDefinitionNode(ClassTypeDefinitionNode classTypeDefinitionNode)
|
||||
{
|
||||
if (_classDefinition.ContainsKey(classTypeDefinitionNode.ClassName) && !classTypeDefinitionNode.IsOverlay)
|
||||
var className = classTypeDefinitionNode.ClassType.TypeName;
|
||||
if (SereinScript.MountType.ContainsKey(className) && !classTypeDefinitionNode.IsOverlay)
|
||||
{
|
||||
//SereinEnv.WriteLine(InfoType.WARN, $"异常信息 : 类型重复定义,代码在第{classTypeDefinitionNode.Row}行: {classTypeDefinitionNode.Code.Trim()}");
|
||||
return;
|
||||
}
|
||||
if(DynamicObjectHelper.GetCacheType(className) == null)
|
||||
{
|
||||
var propertyTypes = classTypeDefinitionNode.Propertys.ToDictionary(p => p.Key, p => symbolInfos[p.Value]);
|
||||
var type = DynamicObjectHelper.CreateTypeWithProperties(propertyTypes, className); // 覆盖
|
||||
SereinScript.MountType[className] = type; // 定义对象
|
||||
}
|
||||
|
||||
//var isOverlay = true; // classTypeDefinitionNode.IsOverlay;
|
||||
|
||||
var type = DynamicObjectHelper.CreateTypeWithProperties(classTypeDefinitionNode.Fields, classTypeDefinitionNode.ClassName); // 覆盖
|
||||
//classTypeDefinitionNode.IsOverlay = false; // 已经加载过,则不再覆盖
|
||||
_classDefinition[classTypeDefinitionNode.ClassName] = type; // 定义对象
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -305,11 +224,11 @@ namespace Serein.Script
|
||||
|
||||
|
||||
// 查找并执行对应的函数
|
||||
if (_functionTable.TryGetValue(funcName, out DelegateDetails? function))
|
||||
if (SereinScript.FunctionDelegates .TryGetValue(funcName, out DelegateDetails? function))
|
||||
{
|
||||
if (!function.EmitMethodInfo.IsStatic)
|
||||
{
|
||||
if(_callFuncOfGetObjects.TryGetValue(funcName, out var action))
|
||||
if(SereinScript.DelegateInstances.TryGetValue(funcName, out var action))
|
||||
{
|
||||
instance = action.Invoke();// 非静态的方法需要获取相应的实例
|
||||
|
||||
@@ -429,27 +348,34 @@ namespace Serein.Script
|
||||
//if (right == null) throw new SereinSciptException(binOpNode.Right, "右值尝试使用计算 null");
|
||||
return EvaluateBinaryOperation(left, binOpNode.Operator, right);
|
||||
case ObjectInstantiationNode objectInstantiationNode: // 对象实例化
|
||||
if (_classDefinition.TryGetValue(objectInstantiationNode.TypeName,out var type ))
|
||||
if (!SereinScript.MountType.TryGetValue(objectInstantiationNode.Type.TypeName, out var type))
|
||||
{
|
||||
object?[] args = new object[objectInstantiationNode.Arguments.Count];
|
||||
for (int i = 0; i < objectInstantiationNode.Arguments.Count; i++)
|
||||
type = symbolInfos[objectInstantiationNode.Type];
|
||||
if (type is null)
|
||||
{
|
||||
var argNode = objectInstantiationNode.Arguments[i];
|
||||
args[i] = await EvaluateAsync(context, argNode);
|
||||
throw new SereinSciptException(objectInstantiationNode, $"使用了未定义的类型\"{objectInstantiationNode.Type.TypeName}\"");
|
||||
}
|
||||
var obj = Activator.CreateInstance(type,args: args);// 创建对象
|
||||
if (obj == null)
|
||||
{
|
||||
throw new SereinSciptException(objectInstantiationNode, $"类型创建失败\"{objectInstantiationNode.TypeName}\"");
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
else
|
||||
object?[] args = new object[objectInstantiationNode.Arguments.Count];
|
||||
for (int i = 0; i < objectInstantiationNode.Arguments.Count; i++)
|
||||
{
|
||||
|
||||
throw new SereinSciptException(objectInstantiationNode, $"使用了未定义的类型\"{objectInstantiationNode.TypeName}\"");
|
||||
|
||||
var argNode = objectInstantiationNode.Arguments[i];
|
||||
args[i] = await EvaluateAsync(context, argNode);
|
||||
}
|
||||
var obj = Activator.CreateInstance(type, args: args);// 创建对象
|
||||
if (obj == null)
|
||||
{
|
||||
throw new SereinSciptException(objectInstantiationNode, $"类型创建失败\"{objectInstantiationNode.Type.TypeName}\"");
|
||||
}
|
||||
for (int i = 0; i < objectInstantiationNode.CtorAssignments.Count; i++)
|
||||
{
|
||||
var ctorAssignmentNode = objectInstantiationNode.CtorAssignments[i];
|
||||
var propertyName = ctorAssignmentNode.MemberName;
|
||||
var value = await EvaluateAsync(context, ctorAssignmentNode.Value);
|
||||
SetPropertyValue(obj, propertyName, value);
|
||||
}
|
||||
|
||||
return obj;
|
||||
case FunctionCallNode callNode: // 调用方法
|
||||
return await InterpretFunctionCallAsync(context, callNode); // 调用方法返回函数的返回值
|
||||
case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用
|
||||
@@ -570,6 +496,48 @@ namespace Serein.Script
|
||||
}
|
||||
}
|
||||
|
||||
public void SetPropertyValue(object target, string memberName, object? value)
|
||||
{
|
||||
var targetType = target?.GetType();
|
||||
if (targetType is null) return;
|
||||
var propertyInfo = targetType.GetProperty(memberName);
|
||||
if (propertyInfo is null)
|
||||
{
|
||||
var fieldInfo = target?.GetType().GetRuntimeField(memberName);
|
||||
if (fieldInfo is null)
|
||||
{
|
||||
throw new Exception($"类型 {targetType} 对象没有成员\"{memberName}\"");
|
||||
}
|
||||
else
|
||||
{
|
||||
var convertedValue = Convert.ChangeType(value, fieldInfo.FieldType);
|
||||
fieldInfo.SetValue(target, convertedValue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
propertyInfo.SetValue(target, null);
|
||||
return;
|
||||
}
|
||||
var valueTtpe = value.GetType();
|
||||
if (propertyInfo.PropertyType.IsAssignableFrom(valueTtpe))
|
||||
{
|
||||
propertyInfo.SetValue(target, value);
|
||||
}
|
||||
else if (propertyInfo.PropertyType.FullName == valueTtpe.FullName)
|
||||
{
|
||||
propertyInfo.SetValue(target, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"类型 {targetType} 对象成员\"{memberName}\" 赋值时异常");
|
||||
}
|
||||
//var convertedValue = Convert.ChangeType(value, );
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取对象成员
|
||||
/// </summary>
|
||||
|
||||
@@ -126,6 +126,11 @@ namespace Serein.Script
|
||||
Type = type;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"token in {Row} row, type is \"{Type}\", value is \"{Value}\".";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
@@ -26,11 +27,6 @@ namespace Serein.Script
|
||||
/// </summary>
|
||||
public Dictionary<ASTNode, Type> NodeSymbolInfos { get; } = new Dictionary<ASTNode, Type>();
|
||||
|
||||
public SereinScriptTypeAnalysis()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void LoadSymbol(Dictionary<string,Type> identifierNodes)
|
||||
{
|
||||
foreach(var kvp in identifierNodes)
|
||||
@@ -43,7 +39,7 @@ namespace Serein.Script
|
||||
}
|
||||
|
||||
|
||||
public void AnalysisProgramNode(ProgramNode astNode)
|
||||
public void Analysis(ProgramNode astNode)
|
||||
{
|
||||
//NodeSymbolInfos.Clear();
|
||||
for (int i = 0; i < astNode.Statements.Count; i++)
|
||||
@@ -53,7 +49,7 @@ namespace Serein.Script
|
||||
}
|
||||
|
||||
|
||||
var returnNodes = astNode.Statements.Where(node => node is ReturnNode).ToArray();
|
||||
var returnNodes = NodeSymbolInfos.Keys.Where(node => node is ReturnNode).ToArray();
|
||||
if (returnNodes.Length == 0)
|
||||
{
|
||||
NodeSymbolInfos[astNode] = typeof(void); // 程序无返回值
|
||||
@@ -66,7 +62,15 @@ namespace Serein.Script
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
var firstReturnType = NodeSymbolInfos[returnNodes[0]]; // 第一个返回值
|
||||
foreach(var item in returnNodes)
|
||||
{
|
||||
if(NodeSymbolInfos[item] != firstReturnType)
|
||||
{
|
||||
throw new Exception("类型检查异常,存在不同分支返回值类型不一致");
|
||||
}
|
||||
}
|
||||
NodeSymbolInfos[astNode] = NodeSymbolInfos[returnNodes[0]]; // 确定的返回值
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,32 +239,61 @@ namespace Serein.Script
|
||||
case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义
|
||||
Type AnalysisClassTypeDefinitionNode(ClassTypeDefinitionNode classTypeDefinitionNode)
|
||||
{
|
||||
var classType = DynamicObjectHelper.GetCacheType(classTypeDefinitionNode.ClassName);
|
||||
if (classType is null)
|
||||
classType = DynamicObjectHelper.CreateTypeWithProperties(classTypeDefinitionNode.Fields, classTypeDefinitionNode.ClassName);
|
||||
|
||||
var classType = Analysis(classTypeDefinitionNode.ClassType); // 查询类型
|
||||
NodeSymbolInfos[classTypeDefinitionNode] = classType;
|
||||
|
||||
foreach (var kvp in classTypeDefinitionNode.Propertys)
|
||||
{
|
||||
TypeNode propertyNode = kvp.Value;
|
||||
var propertyType = Analysis(propertyNode); // 查询属性类型
|
||||
NodeSymbolInfos[propertyNode] = propertyType;
|
||||
}
|
||||
|
||||
NodeSymbolInfos[classTypeDefinitionNode] = classType;
|
||||
return classType;
|
||||
}
|
||||
return AnalysisClassTypeDefinitionNode(classTypeDefinitionNode);
|
||||
case TypeNode typeNode:
|
||||
Type AnalysisTypeNode(TypeNode typeNode)
|
||||
{
|
||||
// 类型搜寻优先级: 挂载类型 > 脚本中定义类型 > C#类型
|
||||
Type resultType = GetTypeOfString(typeNode.TypeName); // 从自定义类型查询类型
|
||||
NodeSymbolInfos[typeNode] = resultType;
|
||||
return resultType;
|
||||
}
|
||||
return AnalysisTypeNode(typeNode);
|
||||
case ObjectInstantiationNode objectInstantiationNode: // 类型实例化
|
||||
Type AnalysisObjectInstantiationNode(ObjectInstantiationNode objectInstantiationNode)
|
||||
{
|
||||
Type? resultType = null;
|
||||
try
|
||||
Type resultType = Analysis(objectInstantiationNode.Type);
|
||||
foreach(var item in objectInstantiationNode.CtorAssignments)
|
||||
{
|
||||
resultType = Type.GetType(objectInstantiationNode.TypeName); // 从命名空间查询类型
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (resultType is null)
|
||||
{
|
||||
resultType = DynamicObjectHelper.GetCacheType(objectInstantiationNode.TypeName); // 从自定义类型查询类型
|
||||
}
|
||||
Analysis(item);
|
||||
}
|
||||
NodeSymbolInfos[objectInstantiationNode] = resultType;
|
||||
return resultType;
|
||||
}
|
||||
return AnalysisObjectInstantiationNode(objectInstantiationNode);
|
||||
case CtorAssignmentNode ctorAssignmentNode: // 构造器赋值
|
||||
Type AnalysisCtorAssignmentNode(CtorAssignmentNode ctorAssignmentNode)
|
||||
{
|
||||
Type classType = Analysis(ctorAssignmentNode.Class);
|
||||
Type valueType = Analysis(ctorAssignmentNode.Value);
|
||||
//ctorAssignmentNode.MemberName
|
||||
var property = classType.GetProperty(ctorAssignmentNode.MemberName);
|
||||
if (property is null)
|
||||
throw new Exception($"类型 {classType} 没有成员 {ctorAssignmentNode.MemberName}");
|
||||
var propertyType = property.PropertyType;
|
||||
if (!propertyType.IsAssignableFrom(valueType))
|
||||
throw new Exception($"类型异常:构造器赋值需要 {propertyType},实际为 {valueType}");
|
||||
|
||||
NodeSymbolInfos[ctorAssignmentNode.Class] = classType;
|
||||
NodeSymbolInfos[ctorAssignmentNode.Value] = valueType;
|
||||
NodeSymbolInfos[ctorAssignmentNode] = propertyType;
|
||||
return valueType;
|
||||
}
|
||||
return AnalysisCtorAssignmentNode(ctorAssignmentNode);
|
||||
case ExpressionNode expressionNode: // 类型表达式(链式调用)
|
||||
Type AnalysisObjectMemberExpressionNode(ExpressionNode expressionNode)
|
||||
{
|
||||
@@ -289,16 +322,33 @@ namespace Serein.Script
|
||||
Type AnalysisMemberAssignmentNode(MemberAssignmentNode memberAssignmentNode)
|
||||
{
|
||||
var objectType = Analysis(memberAssignmentNode.Object);
|
||||
var property = objectType.GetProperty(memberAssignmentNode.MemberName);
|
||||
if(property is null)
|
||||
throw new Exception($"类型异常:类型 {objectType} 没有成员 {memberAssignmentNode.MemberName}");
|
||||
var propertyType = property.PropertyType;
|
||||
var valueType = Analysis(memberAssignmentNode.Value);
|
||||
if (!propertyType.IsAssignableFrom(valueType))
|
||||
throw new Exception($"类型异常:赋值需要 {propertyType},实际为 {valueType}");
|
||||
NodeSymbolInfos[memberAssignmentNode.Object] = propertyType;
|
||||
NodeSymbolInfos[memberAssignmentNode.Value] = valueType;
|
||||
NodeSymbolInfos[memberAssignmentNode] = typeof(void);
|
||||
if(objectType == typeof(object))
|
||||
{
|
||||
/*var property = objectType.GetProperty(memberAssignmentNode.MemberName);
|
||||
if (property is null)
|
||||
throw new Exception($"类型异常:类型 {objectType} 没有成员 {memberAssignmentNode.MemberName}");
|
||||
var propertyType = property.PropertyType;
|
||||
var valueType = Analysis(memberAssignmentNode.Value);
|
||||
if (!propertyType.IsAssignableFrom(valueType))
|
||||
throw new Exception($"类型异常:赋值需要 {propertyType},实际为 {valueType}");*/
|
||||
NodeSymbolInfos[memberAssignmentNode.Object] = typeof(object);
|
||||
NodeSymbolInfos[memberAssignmentNode.Value] = typeof(object);
|
||||
NodeSymbolInfos[memberAssignmentNode] = typeof(void);
|
||||
}
|
||||
else
|
||||
{
|
||||
var property = objectType.GetProperty(memberAssignmentNode.MemberName);
|
||||
if (property is null)
|
||||
throw new Exception($"类型异常:类型 {objectType} 没有成员 {memberAssignmentNode.MemberName}");
|
||||
var propertyType = property.PropertyType;
|
||||
var valueType = Analysis(memberAssignmentNode.Value);
|
||||
if (!propertyType.IsAssignableFrom(valueType))
|
||||
throw new Exception($"类型异常:赋值需要 {propertyType},实际为 {valueType}");
|
||||
NodeSymbolInfos[memberAssignmentNode.Object] = propertyType;
|
||||
NodeSymbolInfos[memberAssignmentNode.Value] = valueType;
|
||||
NodeSymbolInfos[memberAssignmentNode] = typeof(void);
|
||||
}
|
||||
|
||||
return typeof(void); // 对象成员赋值语句不产生类型
|
||||
}
|
||||
return AnalysisMemberAssignmentNode(memberAssignmentNode);
|
||||
@@ -319,12 +369,14 @@ namespace Serein.Script
|
||||
NodeSymbolInfos[memberFunctionCallNode.Object] = objectType;
|
||||
NodeSymbolInfos[memberFunctionCallNode] = methodInfo.ReturnType;
|
||||
return methodInfo.ReturnType;
|
||||
|
||||
|
||||
}
|
||||
return AnalysisMemberFunctionCallNode(memberFunctionCallNode);
|
||||
case FunctionCallNode functionCallNode: // 外部挂载的函数调用
|
||||
Type AnalysisFunctionCallNode(FunctionCallNode functionCallNode)
|
||||
{
|
||||
if(!SereinScriptInterpreter.FunctionInfoTable.TryGetValue(functionCallNode.FunctionName, out var methodInfo))
|
||||
if(!SereinScript.FunctionInfos.TryGetValue(functionCallNode.FunctionName, out var methodInfo))
|
||||
{
|
||||
throw new Exception($"脚本没有挂载方法 {functionCallNode.FunctionName}");
|
||||
}
|
||||
@@ -486,6 +538,8 @@ namespace Serein.Script
|
||||
break;
|
||||
case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义
|
||||
break;
|
||||
case TypeNode typeNode: // 类型
|
||||
break;
|
||||
case ObjectInstantiationNode objectInstantiationNode: // 类型实例化
|
||||
break;
|
||||
case ExpressionNode expressionNode: // 类型表达式(链式调用)
|
||||
@@ -504,6 +558,29 @@ namespace Serein.Script
|
||||
}
|
||||
|
||||
|
||||
public static Type GetTypeOfString(string typeName)
|
||||
{
|
||||
Type? resultType = null;
|
||||
resultType = DynamicObjectHelper.GetCacheType(typeName); // 从自定义类型查询类型
|
||||
if (resultType != null)
|
||||
{
|
||||
return resultType;
|
||||
}
|
||||
try
|
||||
{
|
||||
resultType = Type.GetType(typeName); // 从命名空间查询类型
|
||||
if (resultType != null)
|
||||
{
|
||||
return resultType;
|
||||
}
|
||||
throw new InvalidOperationException($"无法匹配类型 {typeName}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ using Serein.NodeFlow.Services;
|
||||
using Serein.Workbench.Api;
|
||||
using Serein.Workbench.Services;
|
||||
using Serein.Workbench.ViewModels;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
@@ -55,6 +56,23 @@ namespace Serein.Workbench
|
||||
// 这里是测试代码,可以删除
|
||||
private async Task LoadLocalProjectAsync()
|
||||
{
|
||||
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 (1 == 11)
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
xmlns:local="clr-namespace:Serein.Workbench.Node.View"
|
||||
xmlns:vm="clr-namespace:Serein.Workbench.Node.ViewModel"
|
||||
xmlns:themes="clr-namespace:Serein.Workbench.Themes"
|
||||
xmlns:avalonEdit="http://icsharpcode.net/sharpdevelop/avalonedit"
|
||||
d:DataContext="{d:DesignInstance vm:ScriptNodeControlViewModel}"
|
||||
mc:Ignorable="d"
|
||||
MinWidth="50">
|
||||
@@ -56,7 +57,17 @@
|
||||
<Button Content="执行" Margin="3,0,1,0" Command="{Binding CommandExecuting}" Height="17.2"></Button>
|
||||
</StackPanel>
|
||||
<themes:MethodDetailsControl Grid.Row="1" x:Name="MethodDetailsControl" MethodDetails="{Binding NodeModel.MethodDetails}" NodeViewModel="{Binding}"/>
|
||||
<TextBox Grid.Row="2" MinHeight="20" MinWidth="100" MaxWidth="270" TextWrapping="Wrap" AcceptsReturn="True" IsEnabled="{Binding IsEnabledOnView}" Text="{Binding Script}"></TextBox>
|
||||
<!--<TextBox Grid.Row="2" MinHeight="20" MinWidth="100" TextWrapping="Wrap" AcceptsReturn="True" IsEnabled="{Binding IsEnabledOnView}" Text="{Binding Script}"></TextBox>-->
|
||||
|
||||
<avalonEdit:TextEditor Grid.Row="2"
|
||||
x:Name="codeEditor"
|
||||
FontFamily="Consolas"
|
||||
FontSize="12"
|
||||
SyntaxHighlighting="C#"
|
||||
TextChanged="codeEditor_TextChanged"
|
||||
ShowLineNumbers="True"
|
||||
Margin="10"/>
|
||||
|
||||
<Grid Grid.Row="3" >
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="50"/>
|
||||
|
||||
@@ -43,6 +43,7 @@ namespace Serein.Workbench.Node.View
|
||||
DataContext = viewModel;
|
||||
viewModel.NodeModel.DisplayName = "[脚本节点]";
|
||||
InitializeComponent();
|
||||
codeEditor.Text = viewModel.Script ?? string.Empty; // 更新代码编辑器内容
|
||||
}
|
||||
|
||||
|
||||
@@ -96,6 +97,11 @@ namespace Serein.Workbench.Node.View
|
||||
return [];
|
||||
}
|
||||
|
||||
private void codeEditor_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
viewModel.Script = codeEditor.Text;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@
|
||||
<PackageReference Include="AvalonEdit" Version="6.3.0.90" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.6" />
|
||||
<!--<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.135" />-->
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
|
||||
|
||||
|
||||
@@ -25,6 +25,9 @@ namespace Serein.Workbench.Views
|
||||
{
|
||||
this.DataContext = App.GetService<Locator>().MainViewModel;
|
||||
InitializeComponent();
|
||||
|
||||
Window window = new System.Windows.Window();
|
||||
window.Show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user