mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-05-02 05:11:27 +08:00
refactot(script) : 调整了脚本执行相关代码(但后续这个脚本会新的DSL被代替),故不再进行调整
This commit is contained in:
@@ -8,15 +8,10 @@ namespace Serein.Script
|
|||||||
public interface IScriptInvokeContext
|
public interface IScriptInvokeContext
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否该退出了(由 TokenSource 控制,用于响应外部发出停止信号)
|
|
||||||
/// </summary>
|
|
||||||
bool IsReturn { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否需要提前返回(用于脚本中提前结束)
|
/// 是否需要提前返回(用于脚本中提前结束)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool IsNeedReturn { get; set; }
|
bool IsReturn { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否严格检查 Null 值 (禁止使用 Null)
|
/// 是否严格检查 Null 值 (禁止使用 Null)
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ namespace Serein.Script.Node
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class TypeNode : ASTNode
|
public class TypeNode : ASTNode
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 类型名称
|
||||||
|
/// </summary>
|
||||||
public string TypeName { get; }
|
public string TypeName { get; }
|
||||||
|
|
||||||
public TypeNode(string typeName)
|
public TypeNode(string typeName)
|
||||||
|
|||||||
23
Serein.Script/Node/UsingNode.cs
Normal file
23
Serein.Script/Node/UsingNode.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Serein.Script.Node
|
||||||
|
{
|
||||||
|
internal class UsingNode : ASTNode
|
||||||
|
{
|
||||||
|
public string Namespace { get; }
|
||||||
|
|
||||||
|
public UsingNode(string @namespace)
|
||||||
|
{
|
||||||
|
Namespace = @namespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"using Namespace";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,11 +21,6 @@ namespace Serein.Script
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private CancellationTokenSource _tokenSource = new CancellationTokenSource();
|
private CancellationTokenSource _tokenSource = new CancellationTokenSource();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否该退出了
|
|
||||||
/// </summary>
|
|
||||||
public bool IsReturn => _tokenSource.IsCancellationRequested;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否严格检查 Null 值 (禁止使用 Null)
|
/// 是否严格检查 Null 值 (禁止使用 Null)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -34,7 +29,7 @@ namespace Serein.Script
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否需要提前返回(用于脚本中提前结束)
|
/// 是否需要提前返回(用于脚本中提前结束)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsNeedReturn { get; set; }
|
public bool IsReturn { get; set; }
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ using System.Reflection;
|
|||||||
|
|
||||||
namespace Serein.Script
|
namespace Serein.Script
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Serein 脚本引擎
|
||||||
|
/// </summary>
|
||||||
public class SereinScript
|
public class SereinScript
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -14,10 +16,17 @@ namespace Serein.Script
|
|||||||
public SereinScriptTypeAnalysis TypeAnalysis { get; } = new SereinScriptTypeAnalysis();
|
public SereinScriptTypeAnalysis TypeAnalysis { get; } = new SereinScriptTypeAnalysis();
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 程序起始节点
|
||||||
|
/// </summary>
|
||||||
private ProgramNode? programNode;
|
private ProgramNode? programNode;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 执行脚本(静态方法)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="script"></param>
|
||||||
|
/// <param name="argTypes"></param>
|
||||||
|
/// <returns></returns>
|
||||||
public static Task<object?> ExecuteAsync(string script, Dictionary<string, Type>? argTypes = null)
|
public static Task<object?> ExecuteAsync(string script, Dictionary<string, Type>? argTypes = null)
|
||||||
{
|
{
|
||||||
SereinScriptParser parser = new SereinScriptParser();
|
SereinScriptParser parser = new SereinScriptParser();
|
||||||
@@ -50,7 +59,22 @@ namespace Serein.Script
|
|||||||
return returnType; // 脚本返回类型
|
return returnType; // 脚本返回类型
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 执行脚本
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="ArgumentNullException"></exception>
|
||||||
|
public async Task<object?> InterpreterAsync()
|
||||||
|
{
|
||||||
|
IScriptInvokeContext context = new ScriptInvokeContext();
|
||||||
|
if (programNode is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(programNode));
|
||||||
|
}
|
||||||
|
Dictionary<ASTNode, Type> symbolInfos = TypeAnalysis.NodeSymbolInfos.ToDictionary();
|
||||||
|
SereinScriptInterpreter Interpreter = new SereinScriptInterpreter(symbolInfos);
|
||||||
|
return await Interpreter.InterpreterAsync(context, programNode);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 执行脚本
|
/// 执行脚本
|
||||||
@@ -73,7 +97,7 @@ namespace Serein.Script
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 转换为 C# 代码,并且附带方法信息
|
/// 转换为 C# 代码,并且附带方法信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="script">脚本</param>
|
/// <param name="mehtodName">脚本</param>
|
||||||
/// <param name="argTypes">挂载的变量</param>
|
/// <param name="argTypes">挂载的变量</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public SereinScriptMethodInfo? ConvertCSharpCode(string mehtodName, Dictionary<string, Type>? argTypes = null)
|
public SereinScriptMethodInfo? ConvertCSharpCode(string mehtodName, Dictionary<string, Type>? argTypes = null)
|
||||||
@@ -163,7 +187,7 @@ namespace Serein.Script
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 挂载类型
|
/// 挂载类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="typeName">函数名称</param>
|
/// <param name="type">类型</param>
|
||||||
/// <param name="typeName">指定类型名称</param>
|
/// <param name="typeName">指定类型名称</param>
|
||||||
public static void AddClassType(Type type, string typeName = "")
|
public static void AddClassType(Type type, string typeName = "")
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ namespace Serein.Script
|
|||||||
foreach (var node in nodes)
|
foreach (var node in nodes)
|
||||||
{
|
{
|
||||||
result = await InterpretAsync(context, node); // 解释每个节点
|
result = await InterpretAsync(context, node); // 解释每个节点
|
||||||
if (context.IsReturn) break; // 如果需要提前返回,则停止执行
|
|
||||||
}
|
}
|
||||||
return result; // 返回最后一个节点的结果
|
return result; // 返回最后一个节点的结果
|
||||||
}
|
}
|
||||||
@@ -41,14 +40,25 @@ namespace Serein.Script
|
|||||||
{
|
{
|
||||||
switch (node)
|
switch (node)
|
||||||
{
|
{
|
||||||
|
case UsingNode usingNode: // 程序开始节点
|
||||||
|
return null;
|
||||||
case ProgramNode programNode: // 程序开始节点
|
case ProgramNode programNode: // 程序开始节点
|
||||||
throw new Exception();
|
throw new Exception();
|
||||||
case ReturnNode returnNode: // 程序退出节点
|
case ReturnNode returnNode: // 程序退出节点
|
||||||
async Task<object?> InterpreterReturnNodeAsync(IScriptInvokeContext context, ReturnNode returnNode)
|
async Task<object?> InterpreterReturnNodeAsync(IScriptInvokeContext context, ReturnNode returnNode)
|
||||||
{
|
{
|
||||||
object? returnValue = await InterpretAsync(context, returnNode.Value);
|
var node = returnNode.Value;
|
||||||
context.IsNeedReturn = true;
|
context.IsReturn = true;
|
||||||
return returnValue;
|
if (node is null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
object? returnValue = await InterpretAsync(context, node);
|
||||||
|
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return await InterpreterReturnNodeAsync(context, returnNode);
|
return await InterpreterReturnNodeAsync(context, returnNode);
|
||||||
#region 字面量节点
|
#region 字面量节点
|
||||||
@@ -86,7 +96,7 @@ namespace Serein.Script
|
|||||||
data = await InterpretAsync(context, branchNode);
|
data = await InterpretAsync(context, branchNode);
|
||||||
if (branchNode is ReturnNode) // 遇到 Return 语句 提前退出
|
if (branchNode is ReturnNode) // 遇到 Return 语句 提前退出
|
||||||
{
|
{
|
||||||
context.IsNeedReturn = true;
|
context.IsReturn = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,7 +119,7 @@ namespace Serein.Script
|
|||||||
data = await InterpretAsync(context, node);
|
data = await InterpretAsync(context, node);
|
||||||
if (node is ReturnNode) // 遇到 Return 语句 提前退出
|
if (node is ReturnNode) // 遇到 Return 语句 提前退出
|
||||||
{
|
{
|
||||||
context.IsNeedReturn = true;
|
context.IsReturn = true;
|
||||||
break ;
|
break ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -156,6 +156,7 @@ namespace Serein.Script
|
|||||||
"while",
|
"while",
|
||||||
"new",
|
"new",
|
||||||
"class",
|
"class",
|
||||||
|
"using",
|
||||||
];
|
];
|
||||||
|
|
||||||
internal SereinScriptLexer(string input)
|
internal SereinScriptLexer(string input)
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ namespace Serein.Script
|
|||||||
private SereinScriptLexer _lexer;
|
private SereinScriptLexer _lexer;
|
||||||
private Token _currentToken;
|
private Token _currentToken;
|
||||||
|
|
||||||
|
|
||||||
public SereinScriptParser()
|
public SereinScriptParser()
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -32,7 +31,16 @@ namespace Serein.Script
|
|||||||
return Program();
|
return Program();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ASTNode> Statements { get; } = new List<ASTNode>();
|
|
||||||
|
/// <summary>
|
||||||
|
/// 命名空间
|
||||||
|
/// </summary>
|
||||||
|
public List<string> UsingNamespaces { get; } = new List<string>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 程序节点
|
||||||
|
/// </summary>
|
||||||
|
public List<ASTNode> Statements { get; } = new List<ASTNode>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 解析整个程序,直到遇到文件结尾(EOF)为止。
|
/// 解析整个程序,直到遇到文件结尾(EOF)为止。
|
||||||
@@ -122,7 +130,6 @@ namespace Serein.Script
|
|||||||
#region 生成赋值语句/一般语句的ASTNode
|
#region 生成赋值语句/一般语句的ASTNode
|
||||||
if (isAssignment)
|
if (isAssignment)
|
||||||
{
|
{
|
||||||
|
|
||||||
// 以赋值语句的形式进行处理
|
// 以赋值语句的形式进行处理
|
||||||
var assignmentNode = ParseAssignmentNode(); // 解析复制表达式
|
var assignmentNode = ParseAssignmentNode(); // 解析复制表达式
|
||||||
//if(_currentToken.Type == TokenType.Semicolon)
|
//if(_currentToken.Type == TokenType.Semicolon)
|
||||||
@@ -140,6 +147,12 @@ namespace Serein.Script
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
else if (JudgmentKeyword("using")) // 定义对象
|
||||||
|
{
|
||||||
|
var usingNode = ParseUsingNode();
|
||||||
|
UsingNamespaces.Add(usingNode.Namespace);
|
||||||
|
return usingNode;
|
||||||
|
}
|
||||||
else if (JudgmentKeyword("class")) // 定义对象
|
else if (JudgmentKeyword("class")) // 定义对象
|
||||||
{
|
{
|
||||||
var classDefinitionNode = ParseClassDefinitionNode();
|
var classDefinitionNode = ParseClassDefinitionNode();
|
||||||
@@ -175,6 +188,27 @@ namespace Serein.Script
|
|||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 解析表达式根节点
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
private ASTNode ParserExpRootNode()
|
||||||
|
{
|
||||||
|
var name = _currentToken.Value;
|
||||||
|
foreach(var nsp in UsingNamespaces)
|
||||||
|
{
|
||||||
|
var fullName = $"{nsp}.{name}";
|
||||||
|
var type = SereinScriptTypeAnalysis.GetTypeOfString(fullName);
|
||||||
|
if (type is null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var typeNode = new TypeNode(fullName).SetTokenInfo(_currentToken);
|
||||||
|
return typeNode;
|
||||||
|
}
|
||||||
|
return new IdentifierNode(_currentToken.Value).SetTokenInfo(_currentToken);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 解析赋值语句
|
/// 解析赋值语句
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -213,8 +247,10 @@ namespace Serein.Script
|
|||||||
* */
|
* */
|
||||||
//if (JudgmentOperator(_currentToken, "=")) break; // 退出
|
//if (JudgmentOperator(_currentToken, "=")) break; // 退出
|
||||||
//var tempPeekToken = _lexer.PeekToken();
|
//var tempPeekToken = _lexer.PeekToken();
|
||||||
var backupToken = _currentToken;
|
|
||||||
var targetNode = new IdentifierNode(_currentToken.Value).SetTokenInfo(_currentToken); // 生成 Tagget 标记节点
|
|
||||||
|
var targetNode = ParserExpRootNode(); // 生成 Tagget 标记节点
|
||||||
|
//var targetNode = new IdentifierNode(_currentToken.Value).SetTokenInfo(_currentToken); // 生成 Tagget 标记节点
|
||||||
|
|
||||||
List<ASTNode> nodes = [targetNode];
|
List<ASTNode> nodes = [targetNode];
|
||||||
ASTNode? source;
|
ASTNode? source;
|
||||||
@@ -473,6 +509,34 @@ namespace Serein.Script
|
|||||||
throw new Exception($"解析参数节点后,当前Token类型不符合预期,当前类型为 {_currentToken.Type}。");
|
throw new Exception($"解析参数节点后,当前Token类型不符合预期,当前类型为 {_currentToken.Type}。");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// (不处理分号)
|
||||||
|
/// 1. 引入命名空间
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
private UsingNode ParseUsingNode()
|
||||||
|
{
|
||||||
|
var startIndex = _lexer.GetIndex(); // 从“using”开始锚定代码范围
|
||||||
|
NextToken(); // 消耗“using”关键字,获取类名
|
||||||
|
List<string> namespaceItems = [];
|
||||||
|
while (true) // 遇到 ";" 时结束
|
||||||
|
{
|
||||||
|
string className = _currentToken.Value; // 命名空间
|
||||||
|
namespaceItems.Add(className);
|
||||||
|
if (_currentToken.Type == TokenType.Semicolon)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
NextToken(); // 命名空间
|
||||||
|
}
|
||||||
|
var nsp = string.Join('.', namespaceItems);
|
||||||
|
UsingNode usingNode = new UsingNode(nsp);
|
||||||
|
var usingToken = _currentToken;
|
||||||
|
usingToken.Code = _lexer.GetCoreContent(startIndex); // 收集类型定义的代码。
|
||||||
|
usingNode.SetTokenInfo(usingToken);
|
||||||
|
return usingNode;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// (没有分号)解析类定义
|
/// (没有分号)解析类定义
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ namespace Serein.Script
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class SereinScriptTypeAnalysis
|
public class SereinScriptTypeAnalysis
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 符号表
|
/// 符号表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -100,6 +99,10 @@ namespace Serein.Script
|
|||||||
{
|
{
|
||||||
switch (node)
|
switch (node)
|
||||||
{
|
{
|
||||||
|
case UsingNode usingNode:
|
||||||
|
// 引用命名空间节点,不产生类型
|
||||||
|
NodeSymbolInfos[usingNode] = typeof(void);
|
||||||
|
return typeof(void);
|
||||||
case ProgramNode programNode: // 程序开始节点
|
case ProgramNode programNode: // 程序开始节点
|
||||||
NodeSymbolInfos[programNode] = typeof(void);
|
NodeSymbolInfos[programNode] = typeof(void);
|
||||||
return typeof(void);
|
return typeof(void);
|
||||||
@@ -666,21 +669,37 @@ namespace Serein.Script
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
public static Type GetTypeOfString(string typeName)
|
/// 跳过名称搜索类型
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="typeFullnameName"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="InvalidOperationException"></exception>
|
||||||
|
public static Type GetTypeOfString(string typeFullnameName)
|
||||||
{
|
{
|
||||||
Type? resultType = null;
|
Type? resultType = null;
|
||||||
resultType = DynamicObjectHelper.GetCacheType(typeName); // 从自定义类型查询类型
|
resultType = DynamicObjectHelper.GetCacheType(typeFullnameName); // 从自定义类型查询类型
|
||||||
if (resultType != null)
|
if (resultType != null)
|
||||||
{
|
{
|
||||||
return resultType;
|
return resultType;
|
||||||
}
|
}
|
||||||
resultType = Type.GetType(typeName); // 从命名空间查询类型
|
|
||||||
|
resultType = Type.GetType(typeFullnameName); // 从命名空间查询类型
|
||||||
if (resultType != null)
|
if (resultType != null)
|
||||||
{
|
{
|
||||||
return resultType;
|
return resultType;
|
||||||
}
|
}
|
||||||
throw new InvalidOperationException($"无法匹配类型 {typeName}");
|
|
||||||
|
if(SereinEnv.Environment is not null && SereinEnv.Environment.FlowLibraryService is not null)
|
||||||
|
{
|
||||||
|
resultType = SereinEnv.Environment.FlowLibraryService.GetType(typeFullnameName);
|
||||||
|
if (resultType != null)
|
||||||
|
{
|
||||||
|
return resultType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidOperationException($"无法匹配类型 {typeFullnameName}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user