mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-02 15:50:47 +08:00
修复了脚本语言中构造器赋值的 bug
This commit is contained in:
@@ -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; }
|
||||
|
||||
/// <summary>
|
||||
/// 字段名称及字段类型(Kvp[fididName:fidleTypeName])
|
||||
/// </summary>
|
||||
public Dictionary<string, string> FieldInfos { get; }
|
||||
public Dictionary<string, TypeNode> Propertys { 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,98 +18,15 @@ namespace Serein.Script
|
||||
/// </summary>
|
||||
public class SereinScriptInterpreter
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 挂载的函数
|
||||
/// </summary>
|
||||
private static Dictionary<string, DelegateDetails> _functionTable = new Dictionary<string, DelegateDetails>();
|
||||
private static Dictionary<string, MethodInfo> _functionInfoTable = new Dictionary<string, MethodInfo>();
|
||||
private readonly Dictionary<ASTNode, Type> symbolInfos;
|
||||
|
||||
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>
|
||||
/// 入口节点
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
//var isOverlay = true; // classTypeDefinitionNode.IsOverlay;
|
||||
|
||||
var type = DynamicObjectHelper.CreateTypeWithProperties(classTypeDefinitionNode.Fields, classTypeDefinitionNode.ClassName); // 覆盖
|
||||
//classTypeDefinitionNode.IsOverlay = false; // 已经加载过,则不再覆盖
|
||||
_classDefinition[classTypeDefinitionNode.ClassName] = type; // 定义对象
|
||||
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; // 定义对象
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <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++)
|
||||
@@ -52,8 +48,8 @@ namespace Serein.Script
|
||||
Analysis(node);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user