mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-04-03 14:56:34 +08:00
修复了脚本语言中构造器赋值的 bug
This commit is contained in:
@@ -5,6 +5,7 @@ using System.Reflection.Emit;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
namespace Serein.Library.Utils
|
namespace Serein.Library.Utils
|
||||||
{
|
{
|
||||||
@@ -188,8 +189,142 @@ namespace Serein.Library.Utils
|
|||||||
return dynamicType;
|
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 动态创建对象并赋值
|
#region 动态创建对象并赋值
|
||||||
|
|
||||||
// 方法 1: 创建动态类型及其对象实例
|
// 方法 1: 创建动态类型及其对象实例
|
||||||
|
|||||||
@@ -33,19 +33,20 @@ namespace Serein.NodeFlow.Model
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public override bool IsBase => true;
|
public override bool IsBase => true;
|
||||||
|
|
||||||
private IScriptFlowApi ScriptFlowApi;
|
|
||||||
private ProgramNode programNode;
|
|
||||||
private readonly SereinScriptInterpreter scriptInterpreter;
|
|
||||||
private bool IsScriptChanged = false;
|
private bool IsScriptChanged = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 脚本解释器
|
||||||
|
/// </summary>
|
||||||
|
private readonly SereinScript sereinScript;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构建流程脚本节点
|
/// 构建流程脚本节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="environment"></param>
|
/// <param name="environment"></param>
|
||||||
public SingleScriptNode(IFlowEnvironment environment):base(environment)
|
public SingleScriptNode(IFlowEnvironment environment) : base(environment)
|
||||||
{
|
{
|
||||||
ScriptFlowApi = new ScriptFlowApi(environment, this);
|
sereinScript = new SereinScript();
|
||||||
scriptInterpreter = new SereinScriptInterpreter();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static SingleScriptNode()
|
static SingleScriptNode()
|
||||||
@@ -60,7 +61,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
// 加载基础方法
|
// 加载基础方法
|
||||||
foreach ((string name, MethodInfo method) item in tempMethods)
|
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);
|
varNames.Add(pd.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*var sb = new StringBuilder();
|
Dictionary<string, Type> dict = MethodDetails.ParameterDetailss.ToDictionary(pd => pd.Name, pd => pd.DataType); // 准备预定义类型
|
||||||
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); // 开始解析获取程序主节点
|
|
||||||
|
|
||||||
var dict = MethodDetails.ParameterDetailss.ToDictionary(pd => pd.Name, pd => pd.DataType);
|
var returnType = sereinScript.ParserScript(dict, Script); // 开始解析获取程序主节点
|
||||||
typeAnalysis.NodeSymbolInfos.Clear(); // 清空符号表
|
|
||||||
typeAnalysis.LoadSymbol(dict); // 提前加载脚本节点定义的符号
|
|
||||||
typeAnalysis.AnalysisProgramNode(programNode); // 分析节点类型
|
|
||||||
var returnType = typeAnalysis.NodeSymbolInfos[programNode]; // 获取返回类型
|
|
||||||
MethodDetails.ReturnType = returnType;
|
MethodDetails.ReturnType = returnType;
|
||||||
//scriptInterpreter.SetTypeAnalysis(typeAnalysis); // 设置类型分析器
|
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -244,8 +231,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
|
|
||||||
if (token.IsCancellationRequested) return null;
|
if (token.IsCancellationRequested) return null;
|
||||||
|
|
||||||
|
var result = await sereinScript.InterpreterAsync(scriptContext); // 从入口节点执行
|
||||||
var result = await scriptInterpreter.InterpretAsync(scriptContext, programNode); // 从入口节点执行
|
|
||||||
envEvent.FlowRunComplete -= onFlowStop;
|
envEvent.FlowRunComplete -= onFlowStop;
|
||||||
return new FlowResult(this.Guid, context, result);
|
return new FlowResult(this.Guid, context, result);
|
||||||
}
|
}
|
||||||
@@ -259,12 +245,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
|
|
||||||
private static class ScriptBaseFunc
|
private static class ScriptBaseFunc
|
||||||
{
|
{
|
||||||
public static DateTime GetNow() => DateTime.Now;
|
public static DateTime now() => DateTime.Now;
|
||||||
|
|
||||||
public static int Add(int Left, int Right)
|
|
||||||
{
|
|
||||||
return Left + Right;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region 常用的类型转换
|
#region 常用的类型转换
|
||||||
public static bool @bool(object value)
|
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)
|
public static Type type(object type)
|
||||||
{
|
{
|
||||||
return type.GetType();
|
return type.GetType();
|
||||||
|
|||||||
@@ -15,41 +15,40 @@ namespace Serein.Script.Node
|
|||||||
public bool IsOverlay { get; set; }
|
public bool IsOverlay { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 类名称
|
/// 类型名称
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string ClassName { get; }
|
public TypeNode ClassType { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 字段名称及字段类型
|
/// 类型中的属性
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Obsolete("此属性已经过时,将会改为Dictionary<string, string>", false)]
|
public Dictionary<string, TypeNode> Propertys { get; }
|
||||||
public Dictionary<string, Type> Fields { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
public ClassTypeDefinitionNode(Dictionary<string, TypeNode> propertys, TypeNode className)
|
||||||
/// 字段名称及字段类型(Kvp[fididName:fidleTypeName])
|
|
||||||
/// </summary>
|
|
||||||
public Dictionary<string, string> FieldInfos { get; }
|
|
||||||
|
|
||||||
public ClassTypeDefinitionNode(Dictionary<string, string> fields, string className)
|
|
||||||
{
|
{
|
||||||
this.FieldInfos = fields;
|
this.Propertys = propertys;
|
||||||
this.ClassName = className;
|
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)
|
|
||||||
{
|
/* /// <summary>
|
||||||
this.Fields = fields;
|
/// 字段名称及字段类型
|
||||||
this.ClassName = className;
|
/// </summary>
|
||||||
IsOverlay = isOverlay;
|
[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
|
public class ObjectInstantiationNode : ASTNode
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 类型名称
|
/// 类型来源
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string TypeName { get; }
|
public TypeNode Type { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造方法的参数来源
|
/// 构造方法的参数来源
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<ASTNode> Arguments { get; }
|
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;
|
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>
|
/// </summary>
|
||||||
public class SereinScriptInterpreter
|
public class SereinScriptInterpreter
|
||||||
{
|
{
|
||||||
|
private readonly Dictionary<ASTNode, Type> symbolInfos;
|
||||||
|
|
||||||
/// <summary>
|
public SereinScriptInterpreter(Dictionary<ASTNode, Type> symbolInfos)
|
||||||
/// 挂载的函数
|
|
||||||
/// </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)
|
|
||||||
{
|
{
|
||||||
_functionTable[functionName] = new DelegateDetails(methodInfo);
|
this.symbolInfos = symbolInfos;
|
||||||
_functionInfoTable[functionName] = methodInfo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <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>
|
||||||
/// 入口节点
|
/// 入口节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -159,17 +76,19 @@ namespace Serein.Script
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private void ExecutionClassTypeDefinitionNode(ClassTypeDefinitionNode classTypeDefinitionNode)
|
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()}");
|
//SereinEnv.WriteLine(InfoType.WARN, $"异常信息 : 类型重复定义,代码在第{classTypeDefinitionNode.Row}行: {classTypeDefinitionNode.Code.Trim()}");
|
||||||
return;
|
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>
|
/// <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 (!function.EmitMethodInfo.IsStatic)
|
||||||
{
|
{
|
||||||
if(_callFuncOfGetObjects.TryGetValue(funcName, out var action))
|
if(SereinScript.DelegateInstances.TryGetValue(funcName, out var action))
|
||||||
{
|
{
|
||||||
instance = action.Invoke();// 非静态的方法需要获取相应的实例
|
instance = action.Invoke();// 非静态的方法需要获取相应的实例
|
||||||
|
|
||||||
@@ -429,27 +348,34 @@ namespace Serein.Script
|
|||||||
//if (right == null) throw new SereinSciptException(binOpNode.Right, "右值尝试使用计算 null");
|
//if (right == null) throw new SereinSciptException(binOpNode.Right, "右值尝试使用计算 null");
|
||||||
return EvaluateBinaryOperation(left, binOpNode.Operator, right);
|
return EvaluateBinaryOperation(left, binOpNode.Operator, right);
|
||||||
case ObjectInstantiationNode objectInstantiationNode: // 对象实例化
|
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];
|
type = symbolInfos[objectInstantiationNode.Type];
|
||||||
for (int i = 0; i < objectInstantiationNode.Arguments.Count; i++)
|
if (type is null)
|
||||||
{
|
{
|
||||||
var argNode = objectInstantiationNode.Arguments[i];
|
throw new SereinSciptException(objectInstantiationNode, $"使用了未定义的类型\"{objectInstantiationNode.Type.TypeName}\"");
|
||||||
args[i] = await EvaluateAsync(context, argNode);
|
|
||||||
}
|
}
|
||||||
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++)
|
||||||
{
|
{
|
||||||
|
var argNode = objectInstantiationNode.Arguments[i];
|
||||||
throw new SereinSciptException(objectInstantiationNode, $"使用了未定义的类型\"{objectInstantiationNode.TypeName}\"");
|
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: // 调用方法
|
case FunctionCallNode callNode: // 调用方法
|
||||||
return await InterpretFunctionCallAsync(context, callNode); // 调用方法返回函数的返回值
|
return await InterpretFunctionCallAsync(context, callNode); // 调用方法返回函数的返回值
|
||||||
case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用
|
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>
|
||||||
/// 获取对象成员
|
/// 获取对象成员
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -126,6 +126,11 @@ namespace Serein.Script
|
|||||||
Type = type;
|
Type = type;
|
||||||
Value = value;
|
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.Linq;
|
||||||
using System.Reactive;
|
using System.Reactive;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Reflection.Emit;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
@@ -26,11 +27,6 @@ namespace Serein.Script
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<ASTNode, Type> NodeSymbolInfos { get; } = new Dictionary<ASTNode, Type>();
|
public Dictionary<ASTNode, Type> NodeSymbolInfos { get; } = new Dictionary<ASTNode, Type>();
|
||||||
|
|
||||||
public SereinScriptTypeAnalysis()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LoadSymbol(Dictionary<string,Type> identifierNodes)
|
public void LoadSymbol(Dictionary<string,Type> identifierNodes)
|
||||||
{
|
{
|
||||||
foreach(var kvp in 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();
|
//NodeSymbolInfos.Clear();
|
||||||
for (int i = 0; i < astNode.Statements.Count; i++)
|
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)
|
if (returnNodes.Length == 0)
|
||||||
{
|
{
|
||||||
NodeSymbolInfos[astNode] = typeof(void); // 程序无返回值
|
NodeSymbolInfos[astNode] = typeof(void); // 程序无返回值
|
||||||
@@ -66,7 +62,15 @@ namespace Serein.Script
|
|||||||
}
|
}
|
||||||
else
|
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: // 类型定义
|
case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义
|
||||||
Type AnalysisClassTypeDefinitionNode(ClassTypeDefinitionNode classTypeDefinitionNode)
|
Type AnalysisClassTypeDefinitionNode(ClassTypeDefinitionNode classTypeDefinitionNode)
|
||||||
{
|
{
|
||||||
var classType = DynamicObjectHelper.GetCacheType(classTypeDefinitionNode.ClassName);
|
|
||||||
if (classType is null)
|
var classType = Analysis(classTypeDefinitionNode.ClassType); // 查询类型
|
||||||
classType = DynamicObjectHelper.CreateTypeWithProperties(classTypeDefinitionNode.Fields, classTypeDefinitionNode.ClassName);
|
NodeSymbolInfos[classTypeDefinitionNode] = classType;
|
||||||
|
|
||||||
|
foreach (var kvp in classTypeDefinitionNode.Propertys)
|
||||||
|
{
|
||||||
|
TypeNode propertyNode = kvp.Value;
|
||||||
|
var propertyType = Analysis(propertyNode); // 查询属性类型
|
||||||
|
NodeSymbolInfos[propertyNode] = propertyType;
|
||||||
|
}
|
||||||
|
|
||||||
NodeSymbolInfos[classTypeDefinitionNode] = classType;
|
NodeSymbolInfos[classTypeDefinitionNode] = classType;
|
||||||
return classType;
|
return classType;
|
||||||
}
|
}
|
||||||
return AnalysisClassTypeDefinitionNode(classTypeDefinitionNode);
|
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: // 类型实例化
|
case ObjectInstantiationNode objectInstantiationNode: // 类型实例化
|
||||||
Type AnalysisObjectInstantiationNode(ObjectInstantiationNode objectInstantiationNode)
|
Type AnalysisObjectInstantiationNode(ObjectInstantiationNode objectInstantiationNode)
|
||||||
{
|
{
|
||||||
Type? resultType = null;
|
Type resultType = Analysis(objectInstantiationNode.Type);
|
||||||
try
|
foreach(var item in objectInstantiationNode.CtorAssignments)
|
||||||
{
|
{
|
||||||
resultType = Type.GetType(objectInstantiationNode.TypeName); // 从命名空间查询类型
|
Analysis(item);
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (resultType is null)
|
|
||||||
{
|
|
||||||
resultType = DynamicObjectHelper.GetCacheType(objectInstantiationNode.TypeName); // 从自定义类型查询类型
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
NodeSymbolInfos[objectInstantiationNode] = resultType;
|
NodeSymbolInfos[objectInstantiationNode] = resultType;
|
||||||
return resultType;
|
return resultType;
|
||||||
}
|
}
|
||||||
return AnalysisObjectInstantiationNode(objectInstantiationNode);
|
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: // 类型表达式(链式调用)
|
case ExpressionNode expressionNode: // 类型表达式(链式调用)
|
||||||
Type AnalysisObjectMemberExpressionNode(ExpressionNode expressionNode)
|
Type AnalysisObjectMemberExpressionNode(ExpressionNode expressionNode)
|
||||||
{
|
{
|
||||||
@@ -289,16 +322,33 @@ namespace Serein.Script
|
|||||||
Type AnalysisMemberAssignmentNode(MemberAssignmentNode memberAssignmentNode)
|
Type AnalysisMemberAssignmentNode(MemberAssignmentNode memberAssignmentNode)
|
||||||
{
|
{
|
||||||
var objectType = Analysis(memberAssignmentNode.Object);
|
var objectType = Analysis(memberAssignmentNode.Object);
|
||||||
var property = objectType.GetProperty(memberAssignmentNode.MemberName);
|
if(objectType == typeof(object))
|
||||||
if(property is null)
|
{
|
||||||
throw new Exception($"类型异常:类型 {objectType} 没有成员 {memberAssignmentNode.MemberName}");
|
/*var property = objectType.GetProperty(memberAssignmentNode.MemberName);
|
||||||
var propertyType = property.PropertyType;
|
if (property is null)
|
||||||
var valueType = Analysis(memberAssignmentNode.Value);
|
throw new Exception($"类型异常:类型 {objectType} 没有成员 {memberAssignmentNode.MemberName}");
|
||||||
if (!propertyType.IsAssignableFrom(valueType))
|
var propertyType = property.PropertyType;
|
||||||
throw new Exception($"类型异常:赋值需要 {propertyType},实际为 {valueType}");
|
var valueType = Analysis(memberAssignmentNode.Value);
|
||||||
NodeSymbolInfos[memberAssignmentNode.Object] = propertyType;
|
if (!propertyType.IsAssignableFrom(valueType))
|
||||||
NodeSymbolInfos[memberAssignmentNode.Value] = valueType;
|
throw new Exception($"类型异常:赋值需要 {propertyType},实际为 {valueType}");*/
|
||||||
NodeSymbolInfos[memberAssignmentNode] = typeof(void);
|
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 typeof(void); // 对象成员赋值语句不产生类型
|
||||||
}
|
}
|
||||||
return AnalysisMemberAssignmentNode(memberAssignmentNode);
|
return AnalysisMemberAssignmentNode(memberAssignmentNode);
|
||||||
@@ -319,12 +369,14 @@ namespace Serein.Script
|
|||||||
NodeSymbolInfos[memberFunctionCallNode.Object] = objectType;
|
NodeSymbolInfos[memberFunctionCallNode.Object] = objectType;
|
||||||
NodeSymbolInfos[memberFunctionCallNode] = methodInfo.ReturnType;
|
NodeSymbolInfos[memberFunctionCallNode] = methodInfo.ReturnType;
|
||||||
return methodInfo.ReturnType;
|
return methodInfo.ReturnType;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return AnalysisMemberFunctionCallNode(memberFunctionCallNode);
|
return AnalysisMemberFunctionCallNode(memberFunctionCallNode);
|
||||||
case FunctionCallNode functionCallNode: // 外部挂载的函数调用
|
case FunctionCallNode functionCallNode: // 外部挂载的函数调用
|
||||||
Type AnalysisFunctionCallNode(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}");
|
throw new Exception($"脚本没有挂载方法 {functionCallNode.FunctionName}");
|
||||||
}
|
}
|
||||||
@@ -486,6 +538,8 @@ namespace Serein.Script
|
|||||||
break;
|
break;
|
||||||
case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义
|
case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义
|
||||||
break;
|
break;
|
||||||
|
case TypeNode typeNode: // 类型
|
||||||
|
break;
|
||||||
case ObjectInstantiationNode objectInstantiationNode: // 类型实例化
|
case ObjectInstantiationNode objectInstantiationNode: // 类型实例化
|
||||||
break;
|
break;
|
||||||
case ExpressionNode expressionNode: // 类型表达式(链式调用)
|
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.Api;
|
||||||
using Serein.Workbench.Services;
|
using Serein.Workbench.Services;
|
||||||
using Serein.Workbench.ViewModels;
|
using Serein.Workbench.ViewModels;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
@@ -55,6 +56,23 @@ namespace Serein.Workbench
|
|||||||
// 这里是测试代码,可以删除
|
// 这里是测试代码,可以删除
|
||||||
private async Task LoadLocalProjectAsync()
|
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)
|
if (1 == 11)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
xmlns:local="clr-namespace:Serein.Workbench.Node.View"
|
xmlns:local="clr-namespace:Serein.Workbench.Node.View"
|
||||||
xmlns:vm="clr-namespace:Serein.Workbench.Node.ViewModel"
|
xmlns:vm="clr-namespace:Serein.Workbench.Node.ViewModel"
|
||||||
xmlns:themes="clr-namespace:Serein.Workbench.Themes"
|
xmlns:themes="clr-namespace:Serein.Workbench.Themes"
|
||||||
|
xmlns:avalonEdit="http://icsharpcode.net/sharpdevelop/avalonedit"
|
||||||
d:DataContext="{d:DesignInstance vm:ScriptNodeControlViewModel}"
|
d:DataContext="{d:DesignInstance vm:ScriptNodeControlViewModel}"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
MinWidth="50">
|
MinWidth="50">
|
||||||
@@ -56,7 +57,17 @@
|
|||||||
<Button Content="执行" Margin="3,0,1,0" Command="{Binding CommandExecuting}" Height="17.2"></Button>
|
<Button Content="执行" Margin="3,0,1,0" Command="{Binding CommandExecuting}" Height="17.2"></Button>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<themes:MethodDetailsControl Grid.Row="1" x:Name="MethodDetailsControl" MethodDetails="{Binding NodeModel.MethodDetails}" NodeViewModel="{Binding}"/>
|
<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 Grid.Row="3" >
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="50"/>
|
<ColumnDefinition Width="50"/>
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ namespace Serein.Workbench.Node.View
|
|||||||
DataContext = viewModel;
|
DataContext = viewModel;
|
||||||
viewModel.NodeModel.DisplayName = "[脚本节点]";
|
viewModel.NodeModel.DisplayName = "[脚本节点]";
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
codeEditor.Text = viewModel.Script ?? string.Empty; // 更新代码编辑器内容
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -96,6 +97,11 @@ namespace Serein.Workbench.Node.View
|
|||||||
return [];
|
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="AvalonEdit" Version="6.3.0.90" />
|
||||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.6" />
|
<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" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ namespace Serein.Workbench.Views
|
|||||||
{
|
{
|
||||||
this.DataContext = App.GetService<Locator>().MainViewModel;
|
this.DataContext = App.GetService<Locator>().MainViewModel;
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
Window window = new System.Windows.Window();
|
||||||
|
window.Show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user