Files
serein-flow/Serein.Script/SereinScriptInterpreter.cs
fengjiayi 827a9242ae 1. Script项目添加了数组表达式的支持
2. EmitHelper添加了数组创建委托的构建
2025-07-31 11:21:49 +08:00

545 lines
30 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Serein.Library;
using Serein.Library.Utils;
using Serein.Script.Node;
using Serein.Script.Node.FlowControl;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace Serein.Script
{
/// <summary>
/// 脚本解释器,负责执行 Serein 脚本
/// </summary>
public class SereinScriptInterpreter
{
private readonly Dictionary<ASTNode, Type> symbolInfos;
/// <summary>
/// 缓存对象方法调用节点
/// </summary>
//private Dictionary<MemberFunctionCallNode, DelegateDetails> MethodNodeDelegateCaches { get; } = new Dictionary<MemberFunctionCallNode, DelegateDetails>();
private static Dictionary<ASTNode, DelegateDetails> ASTDelegateDetails { get; } = new Dictionary<ASTNode, DelegateDetails>();
public SereinScriptInterpreter(Dictionary<ASTNode, Type> symbolInfos)
{
this.symbolInfos = symbolInfos;
}
public async Task<object?> InterpreterAsync(IScriptInvokeContext context, ProgramNode programNode)
{
var nodes = programNode.Statements;
object? result = null;
foreach (var node in nodes)
{
result = await InterpretAsync(context, node); // 解释每个节点
if (context.IsReturn) break; // 如果需要提前返回,则停止执行
}
return result; // 返回最后一个节点的结果
}
private async Task<object?> InterpretAsync(IScriptInvokeContext context, ASTNode node)
{
switch (node)
{
case ProgramNode programNode: // 程序开始节点
throw new Exception();
case ReturnNode returnNode: // 程序退出节点
async Task<object?> InterpreterReturnNodeAsync(IScriptInvokeContext context, ReturnNode returnNode)
{
object? returnValue = await InterpretAsync(context, returnNode.Value);
context.IsNeedReturn = true;
return returnValue;
}
return await InterpreterReturnNodeAsync(context, returnNode);
#region
case NullNode nullNode: // null
return null; // 返回 null
case CharNode charNode: // char字面量
return charNode.Value; // 返回字符值
case StringNode stringNode: // 字符串字面量
return stringNode.Value; // 返回字符串值
case BooleanNode booleanNode: // 布尔值字面量
return booleanNode.Value; // 返回布尔值
case NumberIntNode numberIntNode: // int整型数值字面量
return numberIntNode.Value; // 返回 int 整型数值
case NumberLongNode numberLongNode: // long整型数值字面量
return numberLongNode.Value; // 返回 long 整型数值
case NumberFloatNode numberFloatNode: // float浮点数值字面量
return numberFloatNode.Value; // 返回 float 浮点数值
case NumberDoubleNode numberDoubleNode: // double浮点数值字面量
return numberDoubleNode.Value; // 返回 double 浮点数值
#endregion
case IdentifierNode identifierNode: // 变量定义
return context.GetVarValue(identifierNode.Name);
case IfNode ifNode: // if语句结构
async Task<object?> InterpreterIfNodeAsync(IScriptInvokeContext context, IfNode ifNode)
{
var result = await InterpretAsync(context, ifNode.Condition) ?? throw new SereinSciptParserException(ifNode, $"条件语句返回了 null");
if (result is not bool condition) throw new SereinSciptParserException(ifNode, "条件语句返回值不为 bool 类型");
var branchNodes = condition ? ifNode.TrueBranch : ifNode.FalseBranch;
if (branchNodes.Count == 0) return default;
object? data = default;
foreach (var branchNode in branchNodes)
{
data = await InterpretAsync(context, branchNode);
if (branchNode is ReturnNode) // 遇到 Return 语句 提前退出
{
context.IsNeedReturn = true;
break;
}
}
return data;
}
return await InterpreterIfNodeAsync(context, ifNode);
case WhileNode whileNode: // while语句结构
async Task<object?> InterpreterWhileNodeAsync(IScriptInvokeContext context, WhileNode whileNode)
{
object? data = default;
while (true)
{
var result = await InterpretAsync(context, whileNode.Condition) ?? throw new SereinSciptParserException(whileNode, $"循环节点条件返回了 null");
if (result is not bool condition) throw new SereinSciptParserException(whileNode, "循环节点条件返回值不为 bool 类型");
if (!condition) break;
if (whileNode.Body.Count == 0) break;
foreach (var node in whileNode.Body)
{
data = await InterpretAsync(context, node);
if (node is ReturnNode) // 遇到 Return 语句 提前退出
{
context.IsNeedReturn = true;
break ;
}
}
}
return data;
}
await InterpreterWhileNodeAsync(context, whileNode);
return default;
case AssignmentNode assignmentNode: // 变量赋值语句
async Task InterpreterAssignmentNodeAsync(IScriptInvokeContext context, AssignmentNode assignmentNode)
{
if (assignmentNode.Target is IdentifierNode identifierNode)
{
var value = await InterpretAsync(context, assignmentNode.Value);
context.SetVarValue(identifierNode.Name, value);
}
}
await InterpreterAssignmentNodeAsync(context, assignmentNode);
return default;
case BinaryOperationNode binaryOperationNode: // 二元运算操作
async Task<object?> InterpreterBinaryOperationNodeAsync(IScriptInvokeContext context, BinaryOperationNode binaryOperationNode)
{
// 递归计算二元操作
var left = await InterpretAsync(context, binaryOperationNode.Left);
if (left == null ) throw new SereinSciptParserException(binaryOperationNode.Left, $"左值尝试使用 null");
var right = await InterpretAsync(context, binaryOperationNode.Right);
if (right == null) throw new SereinSciptParserException(binaryOperationNode.Right, "右值尝试使用计算 null");
var op = binaryOperationNode.Operator;
var result = BinaryOperationEvaluator.EvaluateValue(left, op, right);
return result;
}
return await InterpreterBinaryOperationNodeAsync(context, binaryOperationNode);
case CollectionAssignmentNode collectionAssignmentNode: // 集合赋值节点
async Task InterpreterCollectionAssignmentNodeAsync(IScriptInvokeContext context, CollectionAssignmentNode collectionAssignmentNode)
{
var collectionValue = await InterpretAsync(context, collectionAssignmentNode.Collection.Collection);
if (collectionValue is null)
{
throw new ArgumentNullException($"解析{collectionAssignmentNode}节点时,集合返回空。");
}
var indexValue = await InterpretAsync(context, collectionAssignmentNode.Collection.Index);
if (indexValue is null)
{
throw new ArgumentNullException($"解析{collectionAssignmentNode}节点时,索引返回空。");
}
var valueValue = await InterpretAsync(context, collectionAssignmentNode.Value);
await SetCollectionValueAsync(collectionAssignmentNode, collectionValue, indexValue, valueValue);
}
await InterpreterCollectionAssignmentNodeAsync(context, collectionAssignmentNode);
return default;
case CollectionIndexNode collectionIndexNode: // 集合获取索引对应值
async Task<object?> InterpreterCollectionIndexNodeAsync(IScriptInvokeContext context, CollectionIndexNode collectionIndexNode)
{
var collectionValue = await InterpretAsync(context, collectionIndexNode.Collection);
if (collectionValue is null)
{
throw new ArgumentNullException($"解析{collectionIndexNode}节点时,集合返回空。");
}
var indexValue = await InterpretAsync(context, collectionIndexNode.Index);
if (indexValue is null)
{
throw new ArgumentNullException($"解析{collectionIndexNode}节点时,索引返回空。");
}
var result = await GetCollectionValueAsync(collectionIndexNode, collectionValue, indexValue);
return result;
}
return await InterpreterCollectionIndexNodeAsync(context, collectionIndexNode);
case ArrayDefintionNode arrayDefintionNode:
async Task<Array> InterpreterArrayDefintionNodeAsync(ArrayDefintionNode arrayDefintionNode)
{
var elementNodes = arrayDefintionNode.Elements;
var elementCount = elementNodes.Count;
if(elementCount == 0)
{
return Array.Empty<object>();
}
/*var arrayType = symbolInfos[arrayDefintionNode]; // 从 symbolInfos 中获取数组类型( T[]
var eleType = arrayType.MakeArrayType();*/
/*if (!ASTDelegateDetails.TryGetValue(arrayDefintionNode, out DelegateDetails? delegateDetails))
{
delegateDetails = new DelegateDetails(symbolInfos[elementNodes[0]], DelegateDetails.EmitType.ArrayCreate);
ASTDelegateDetails[arrayDefintionNode] = delegateDetails;
}*/
//var arrobj = await delegateDetails.InvokeAsync(null, [elementCount]);
var elementType1 = symbolInfos[elementNodes[0]];
var array = Array.CreateInstance(elementType1, elementCount);
for (int i = 0; i < elementNodes.Count; i++)
{
var elementNode = elementNodes[i];
var elementType = symbolInfos[elementNode];
var value = await InterpretAsync(context, elementNode);
var c = Convert.ChangeType(value, elementType);
array.SetValue(c, i);
//array[i] = value;
}
return array;
}
return await InterpreterArrayDefintionNodeAsync(arrayDefintionNode);
case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义
void InterpreterClassTypeDefinitionNode(IScriptInvokeContext context, ClassTypeDefinitionNode classTypeDefinitionNode)
{
var className = classTypeDefinitionNode.ClassType.TypeName;
if (SereinScript.MountType.ContainsKey(className))
{
//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; // 定义对象
}
}
InterpreterClassTypeDefinitionNode(context, classTypeDefinitionNode);
return default;
case TypeNode typeNode: // 类型
return default;
case ObjectInstantiationNode objectInstantiationNode: // 类型实例化
async Task<object?> InterpreterObjectInstantiationNodeAsync(IScriptInvokeContext context, ObjectInstantiationNode objectInstantiationNode)
{
if (!SereinScript.MountType.TryGetValue(objectInstantiationNode.Type.TypeName, out var type))
{
type = symbolInfos[objectInstantiationNode.Type];
if (type is null)
{
throw new SereinSciptParserException(objectInstantiationNode, $"使用了未定义的类型\"{objectInstantiationNode.Type.TypeName}\"");
}
}
// 获取参数
var args = objectInstantiationNode.Arguments.Count == 0 ? [] :
(await objectInstantiationNode.Arguments.SelectAsync(
async argNode => await InterpretAsync(context, argNode)))
.ToArray();
var obj = Activator.CreateInstance(type, args: args);// 创建对象
if (obj is null)
{
throw new SereinSciptParserException(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 InterpretAsync(context, ctorAssignmentNode.Value);
await SetPropertyValueAsync(ctorAssignmentNode, obj, propertyName, value);
}
return obj;
}
return await InterpreterObjectInstantiationNodeAsync(context, objectInstantiationNode);
case CtorAssignmentNode ctorAssignmentNode:
return default;
/*case ExpressionNode expressionNode: // 类型表达式(链式调用)
return await InterpretAsync(context, expressionNode.Value); // 直接计算表达式的值*/
case MemberAccessNode memberAccessNode: // 对象成员访问
async Task<object?> InterpreterMemberAccessNodeAsync(IScriptInvokeContext context, MemberAccessNode memberAccessNode)
{
var target = await InterpretAsync(context, memberAccessNode.Object);
var memberName = memberAccessNode.MemberName;
if(target is null) throw new SereinSciptParserException(memberAccessNode, $"无法获取成员,对象为 null \"{memberAccessNode.Object.Code}\"");
var value = await GetPropertyValueAsync(memberAccessNode, target, memberName);
return value;
}
return await InterpreterMemberAccessNodeAsync(context, memberAccessNode);
case MemberAssignmentNode memberAssignmentNode: // 对象成员赋值
async Task<object?> InterpreterMemberAssignmentNodeAsync(IScriptInvokeContext context, MemberAssignmentNode memberAssignmentNode)
{
var target = await InterpretAsync(context, memberAssignmentNode.Object);
var memberName = memberAssignmentNode.MemberName;
var value = await InterpretAsync(context, memberAssignmentNode.Value);
if (target is null) throw new SereinSciptParserException(memberAssignmentNode, $"无法设置成员,对象为 null \"{memberAssignmentNode.Object.Code}\"");
await SetPropertyValueAsync(memberAssignmentNode, target, memberName, value);
return value;
}
return await InterpreterMemberAssignmentNodeAsync(context, memberAssignmentNode);
case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用
async Task<object?> InterpreterMemberFunctionCallNodeAsync(IScriptInvokeContext context, MemberFunctionCallNode memberFunctionCallNode)
{
var target = await InterpretAsync(context, memberFunctionCallNode.Object);
if (!ASTDelegateDetails.TryGetValue(memberFunctionCallNode, out DelegateDetails? delegateDetails))
{
var methodName = memberFunctionCallNode.FunctionName;
var argTypes = (memberFunctionCallNode.Arguments.Count == 0) switch
{
true => [],
false => memberFunctionCallNode.Arguments.Select(arg => symbolInfos[arg]).ToArray()
};
var methodInfo = target?.GetType().GetMethod(methodName, argTypes); // 获取参数列表的类型
if (methodInfo is null) throw new SereinSciptParserException(memberFunctionCallNode, $"对象没有方法\"{memberFunctionCallNode.FunctionName}\"");
delegateDetails = new DelegateDetails(methodInfo);
ASTDelegateDetails[memberFunctionCallNode] = delegateDetails;
} // 查询是否有缓存
// 获取参数
var arguments = memberFunctionCallNode.Arguments.Count == 0 ? [] :
(await memberFunctionCallNode.Arguments.SelectAsync(
async argNode => await InterpretAsync(context, argNode)))
.ToArray();
// 调用方法
var reuslt = await delegateDetails.InvokeAsync(target, arguments);
return reuslt;
}
return await InterpreterMemberFunctionCallNodeAsync(context, memberFunctionCallNode);
case FunctionCallNode functionCallNode: // 外部挂载的函数调用
async Task<object?> InterpreterFunctionCallNodeAsync(IScriptInvokeContext context, FunctionCallNode functionCallNode)
{
// 获取流程上下文
if (context.FlowContext != null && functionCallNode.FunctionName.Equals("getFlowApi", StringComparison.OrdinalIgnoreCase))
{
return context.FlowContext;
}
else if (functionCallNode.FunctionName.Equals("getScriptApi", StringComparison.OrdinalIgnoreCase))
{
return context;
}
// 获取参数
var arguments = functionCallNode.Arguments.Count == 0 ? [] :
(await functionCallNode.Arguments.SelectAsync(
async argNode => await InterpretAsync(context, argNode)))
.ToArray();
var funcName = functionCallNode.FunctionName;
object? instance = null; // 静态方法不需要传入实例所以可以传入null
// 查找并执行对应的函数
if (!SereinScript.FunctionDelegates.TryGetValue(funcName, out DelegateDetails? function))
throw new SereinSciptParserException(functionCallNode, $"没有挂载方法\"{functionCallNode.FunctionName}\"");
/* if (!function.EmitMethodInfo.IsStatic)
{
if (!SereinScript.DelegateInstances.TryGetValue(funcName, out var action))
{
throw new SereinSciptException(functionCallNode, $"挂载方法 {funcName} 时需要同时给定获取实例的 Func<object>");
}
instance = action.Invoke();// 非静态的方法需要获取相应的实例
if (instance is null)
{
throw new SereinSciptException(functionCallNode, $"函数 {funcName} 尝试获取实例时返回了 null ");
}
}*/
var result = await function.InvokeAsync(instance, arguments);
return result;
}
return await InterpreterFunctionCallNodeAsync(context, functionCallNode);
default: // 未定义的节点类型
throw new Exception($"解释器未实现的节点类型 {node.GetType()}");
}
}
/// <summary>
/// 设置对象成员
/// </summary>
/// <param name="node">节点,用于缓存委托避免重复反射</param>
/// <param name="target">对象</param>
/// <param name="memberName">属性名称</param>
/// <param name="value">属性值</param>
/// <exception cref="Exception"></exception>
private async Task SetPropertyValueAsync(ASTNode node, object target, string memberName, object? value)
{
if(ASTDelegateDetails.TryGetValue(node ,out DelegateDetails? delegateDetails))
{
await delegateDetails.InvokeAsync(target, [value]);
return;
}
var targetType = target?.GetType();
if (targetType is null) return;
var propertyInfo = targetType.GetProperty(memberName);
if (propertyInfo is null)
{
FieldInfo? fieldInfo = target?.GetType().GetRuntimeField(memberName);
if (fieldInfo is null)
{
throw new Exception($"类型 {targetType} 对象没有成员\"{memberName}\"");
}
else
{
delegateDetails = new DelegateDetails(fieldInfo, DelegateDetails.GSType.Set);
ASTDelegateDetails[node] = delegateDetails; // 缓存委托
await delegateDetails.InvokeAsync(target, [value]);
//var convertedValue = Convert.ChangeType(value, fieldInfo.FieldType);
//fieldInfo.SetValue(target, convertedValue);
}
}
else
{
delegateDetails = new DelegateDetails(propertyInfo, DelegateDetails.GSType.Set);
ASTDelegateDetails[node] = delegateDetails; // 缓存委托
await delegateDetails.InvokeAsync(target, [value]);
/*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}\" 赋值时异常");
}*/
}
}
/// <summary>
/// 从对象获取值
/// </summary>
/// <param name="node">节点,用于缓存委托避免重复反射</param>
/// <param name="target">对象</param>
/// <param name="memberName">成员名称</param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private async Task<object?> GetPropertyValueAsync(ASTNode node, object target, string memberName)
{
if (ASTDelegateDetails.TryGetValue(node, out DelegateDetails? delegateDetails))
{
var result = await delegateDetails.InvokeAsync(target, []);
return result;
}
var targetType = target?.GetType();
if (targetType is null) return null;
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
{
delegateDetails = new DelegateDetails(propertyInfo, DelegateDetails.GSType.Get);
ASTDelegateDetails[node] = delegateDetails; // 缓存委托
var result = await delegateDetails.InvokeAsync(target, []);
return result;
//return fieldInfo.GetValue(target);
}
}
else
{
delegateDetails = new DelegateDetails(propertyInfo, DelegateDetails.GSType.Get);
ASTDelegateDetails[node] = delegateDetails; // 缓存委托
var result = await delegateDetails.InvokeAsync(target, []);
return result;
//return propertyInfo.GetValue(target);
}
}
/// <summary>
/// 设置集合成员
/// </summary>
/// <param name="node">节点,用于缓存委托避免重复反射</param>
/// <param name="collectionValue"></param>
/// <param name="indexValue"></param>
/// <param name="valueValue"></param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private async Task SetCollectionValueAsync(ASTNode node, object collectionValue, object indexValue, object valueValue)
{
if (ASTDelegateDetails.TryGetValue(node, out DelegateDetails? delegateDetails))
{
await delegateDetails.InvokeAsync(collectionValue, [indexValue, valueValue]);
return;
}
else
{
var collectionType = collectionValue.GetType(); // 目标对象的类型
delegateDetails = new DelegateDetails(collectionType, DelegateDetails.EmitType.CollectionSetter);
ASTDelegateDetails[node] = delegateDetails; // 缓存委托
await delegateDetails.InvokeAsync(collectionValue, [indexValue, valueValue]);
return;
}
}
/// <summary>
/// 获取集合中的成员
/// </summary>
/// <param name="node">节点,用于缓存委托避免重复反射</param>
/// <param name="collectionValue"></param>
/// <param name="indexValue"></param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private async Task<object?> GetCollectionValueAsync(ASTNode node, object collectionValue, object indexValue)
{
if (ASTDelegateDetails.TryGetValue(node, out DelegateDetails? delegateDetails))
{
var result = await delegateDetails.InvokeAsync(collectionValue, [indexValue]);
return result;
}
else
{
// 针对 string 特化
if(collectionValue is string chars && indexValue is int index)
{
return chars[index];
}
var collectionType = collectionValue.GetType(); // 目标对象的类型
delegateDetails = new DelegateDetails(collectionType, DelegateDetails.EmitType.CollectionGetter);
ASTDelegateDetails[node] = delegateDetails; // 缓存委托
var result = await delegateDetails.InvokeAsync(collectionValue, [indexValue]);
return result;
}
}
}
}