diff --git a/Serein.Script/IScriptInvokeContext.cs b/Serein.Script/IScriptInvokeContext.cs index c842a8a..3899098 100644 --- a/Serein.Script/IScriptInvokeContext.cs +++ b/Serein.Script/IScriptInvokeContext.cs @@ -8,15 +8,10 @@ namespace Serein.Script public interface IScriptInvokeContext { - /// - /// 是否该退出了(由 TokenSource 控制,用于响应外部发出停止信号) - /// - bool IsReturn { get; } - /// /// 是否需要提前返回(用于脚本中提前结束) /// - bool IsNeedReturn { get; set; } + bool IsReturn { get; set; } /// /// 是否严格检查 Null 值 (禁止使用 Null) diff --git a/Serein.Script/Node/TypeNode.cs b/Serein.Script/Node/TypeNode.cs index 6e1ca96..0c7705b 100644 --- a/Serein.Script/Node/TypeNode.cs +++ b/Serein.Script/Node/TypeNode.cs @@ -11,6 +11,9 @@ namespace Serein.Script.Node /// public class TypeNode : ASTNode { + /// + /// 类型名称 + /// public string TypeName { get; } public TypeNode(string typeName) diff --git a/Serein.Script/Node/UsingNode.cs b/Serein.Script/Node/UsingNode.cs new file mode 100644 index 0000000..1853150 --- /dev/null +++ b/Serein.Script/Node/UsingNode.cs @@ -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"; + } + } +} diff --git a/Serein.Script/ScriptInvokeContext.cs b/Serein.Script/ScriptInvokeContext.cs index 7ad1b15..100dd8b 100644 --- a/Serein.Script/ScriptInvokeContext.cs +++ b/Serein.Script/ScriptInvokeContext.cs @@ -21,11 +21,6 @@ namespace Serein.Script /// private CancellationTokenSource _tokenSource = new CancellationTokenSource(); - /// - /// 是否该退出了 - /// - public bool IsReturn => _tokenSource.IsCancellationRequested; - /// /// 是否严格检查 Null 值 (禁止使用 Null) /// @@ -34,7 +29,7 @@ namespace Serein.Script /// /// 是否需要提前返回(用于脚本中提前结束) /// - public bool IsNeedReturn { get; set; } + public bool IsReturn { get; set; } /// diff --git a/Serein.Script/SereinScript.cs b/Serein.Script/SereinScript.cs index 300ecb5..34497b6 100644 --- a/Serein.Script/SereinScript.cs +++ b/Serein.Script/SereinScript.cs @@ -5,7 +5,9 @@ using System.Reflection; namespace Serein.Script { - + /// + /// Serein 脚本引擎 + /// public class SereinScript { /// @@ -14,10 +16,17 @@ namespace Serein.Script public SereinScriptTypeAnalysis TypeAnalysis { get; } = new SereinScriptTypeAnalysis(); - + /// + /// 程序起始节点 + /// private ProgramNode? programNode; - + /// + /// 执行脚本(静态方法) + /// + /// + /// + /// public static Task ExecuteAsync(string script, Dictionary? argTypes = null) { SereinScriptParser parser = new SereinScriptParser(); @@ -50,7 +59,22 @@ namespace Serein.Script return returnType; // 脚本返回类型 } - + /// + /// 执行脚本 + /// + /// + /// + public async Task InterpreterAsync() + { + IScriptInvokeContext context = new ScriptInvokeContext(); + if (programNode is null) + { + throw new ArgumentNullException(nameof(programNode)); + } + Dictionary symbolInfos = TypeAnalysis.NodeSymbolInfos.ToDictionary(); + SereinScriptInterpreter Interpreter = new SereinScriptInterpreter(symbolInfos); + return await Interpreter.InterpreterAsync(context, programNode); + } /// /// 执行脚本 @@ -73,7 +97,7 @@ namespace Serein.Script /// /// 转换为 C# 代码,并且附带方法信息 /// - /// 脚本 + /// 脚本 /// 挂载的变量 /// public SereinScriptMethodInfo? ConvertCSharpCode(string mehtodName, Dictionary? argTypes = null) @@ -163,7 +187,7 @@ namespace Serein.Script /// /// 挂载类型 /// - /// 函数名称 + /// 类型 /// 指定类型名称 public static void AddClassType(Type type, string typeName = "") { diff --git a/Serein.Script/SereinScriptInterpreter.cs b/Serein.Script/SereinScriptInterpreter.cs index 8583a3c..47ab65e 100644 --- a/Serein.Script/SereinScriptInterpreter.cs +++ b/Serein.Script/SereinScriptInterpreter.cs @@ -32,7 +32,6 @@ namespace Serein.Script foreach (var node in nodes) { result = await InterpretAsync(context, node); // 解释每个节点 - if (context.IsReturn) break; // 如果需要提前返回,则停止执行 } return result; // 返回最后一个节点的结果 } @@ -41,14 +40,25 @@ namespace Serein.Script { switch (node) { + case UsingNode usingNode: // 程序开始节点 + return null; case ProgramNode programNode: // 程序开始节点 throw new Exception(); case ReturnNode returnNode: // 程序退出节点 async Task InterpreterReturnNodeAsync(IScriptInvokeContext context, ReturnNode returnNode) { - object? returnValue = await InterpretAsync(context, returnNode.Value); - context.IsNeedReturn = true; - return returnValue; + var node = returnNode.Value; + context.IsReturn = true; + if (node is null) + { + return null; + } + else + { + object? returnValue = await InterpretAsync(context, node); + + return returnValue; + } } return await InterpreterReturnNodeAsync(context, returnNode); #region 字面量节点 @@ -86,7 +96,7 @@ namespace Serein.Script data = await InterpretAsync(context, branchNode); if (branchNode is ReturnNode) // 遇到 Return 语句 提前退出 { - context.IsNeedReturn = true; + context.IsReturn = true; break; } } @@ -109,7 +119,7 @@ namespace Serein.Script data = await InterpretAsync(context, node); if (node is ReturnNode) // 遇到 Return 语句 提前退出 { - context.IsNeedReturn = true; + context.IsReturn = true; break ; } } diff --git a/Serein.Script/SereinScriptLexer.cs b/Serein.Script/SereinScriptLexer.cs index dca7162..22ceb90 100644 --- a/Serein.Script/SereinScriptLexer.cs +++ b/Serein.Script/SereinScriptLexer.cs @@ -156,6 +156,7 @@ namespace Serein.Script "while", "new", "class", + "using", ]; internal SereinScriptLexer(string input) diff --git a/Serein.Script/SereinScriptParser.cs b/Serein.Script/SereinScriptParser.cs index c90ab49..1856608 100644 --- a/Serein.Script/SereinScriptParser.cs +++ b/Serein.Script/SereinScriptParser.cs @@ -14,7 +14,6 @@ namespace Serein.Script private SereinScriptLexer _lexer; private Token _currentToken; - public SereinScriptParser() { @@ -32,7 +31,16 @@ namespace Serein.Script return Program(); } - private List Statements { get; } = new List(); + + /// + /// 命名空间 + /// + public List UsingNamespaces { get; } = new List(); + + /// + /// 程序节点 + /// + public List Statements { get; } = new List(); /// /// 解析整个程序,直到遇到文件结尾(EOF)为止。 @@ -122,7 +130,6 @@ namespace Serein.Script #region 生成赋值语句/一般语句的ASTNode if (isAssignment) { - // 以赋值语句的形式进行处理 var assignmentNode = ParseAssignmentNode(); // 解析复制表达式 //if(_currentToken.Type == TokenType.Semicolon) @@ -140,6 +147,12 @@ namespace Serein.Script #endregion } + else if (JudgmentKeyword("using")) // 定义对象 + { + var usingNode = ParseUsingNode(); + UsingNamespaces.Add(usingNode.Namespace); + return usingNode; + } else if (JudgmentKeyword("class")) // 定义对象 { var classDefinitionNode = ParseClassDefinitionNode(); @@ -175,6 +188,27 @@ namespace Serein.Script }*/ } + /// + /// 解析表达式根节点 + /// + /// + 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); + } + /// /// 解析赋值语句 /// @@ -213,8 +247,10 @@ namespace Serein.Script * */ //if (JudgmentOperator(_currentToken, "=")) break; // 退出 //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 nodes = [targetNode]; ASTNode? source; @@ -473,6 +509,34 @@ namespace Serein.Script throw new Exception($"解析参数节点后,当前Token类型不符合预期,当前类型为 {_currentToken.Type}。"); } + /// + /// (不处理分号) + /// 1. 引入命名空间 + /// + /// + private UsingNode ParseUsingNode() + { + var startIndex = _lexer.GetIndex(); // 从“using”开始锚定代码范围 + NextToken(); // 消耗“using”关键字,获取类名 + List 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; + } + /// /// (没有分号)解析类定义 /// diff --git a/Serein.Script/SereinScriptTypeAnalysis.cs b/Serein.Script/SereinScriptTypeAnalysis.cs index 6fd60f7..37af6cd 100644 --- a/Serein.Script/SereinScriptTypeAnalysis.cs +++ b/Serein.Script/SereinScriptTypeAnalysis.cs @@ -23,7 +23,6 @@ namespace Serein.Script /// public class SereinScriptTypeAnalysis { - /// /// 符号表 /// @@ -100,6 +99,10 @@ namespace Serein.Script { switch (node) { + case UsingNode usingNode: + // 引用命名空间节点,不产生类型 + NodeSymbolInfos[usingNode] = typeof(void); + return typeof(void); case ProgramNode programNode: // 程序开始节点 NodeSymbolInfos[programNode] = typeof(void); return typeof(void); @@ -666,21 +669,37 @@ namespace Serein.Script } } - - public static Type GetTypeOfString(string typeName) + /// + /// 跳过名称搜索类型 + /// + /// + /// + /// + public static Type GetTypeOfString(string typeFullnameName) { Type? resultType = null; - resultType = DynamicObjectHelper.GetCacheType(typeName); // 从自定义类型查询类型 + resultType = DynamicObjectHelper.GetCacheType(typeFullnameName); // 从自定义类型查询类型 if (resultType != null) { return resultType; } - resultType = Type.GetType(typeName); // 从命名空间查询类型 + + resultType = Type.GetType(typeFullnameName); // 从命名空间查询类型 if (resultType != null) { 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}"); }