diff --git a/Library/Utils/DynamicObjectHelper.cs b/Library/Utils/DynamicObjectHelper.cs index b52dbdc..95a7c42 100644 --- a/Library/Utils/DynamicObjectHelper.cs +++ b/Library/Utils/DynamicObjectHelper.cs @@ -14,7 +14,17 @@ namespace Serein.Library.Utils public class DynamicObjectHelper { // 类型缓存,键为类型的唯一名称(可以根据实际需求调整生成方式) - static Dictionary typeCache = new Dictionary(); + private static Dictionary typeCache = new Dictionary(); + private static readonly AssemblyBuilder AssemblyBuilder; + private static readonly ModuleBuilder ModuleBuilder; + + static DynamicObjectHelper() // 静态构造函数 + { + var assemblyName = new AssemblyName("DynamicAssembly"); + AssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); + ModuleBuilder = AssemblyBuilder.DefineDynamicModule("MainModule"); + } + /// /// 获取运行时创建过的类型 @@ -82,6 +92,8 @@ namespace Serein.Library.Utils } } + + /// /// 创建具有属性的类型 /// @@ -99,12 +111,12 @@ namespace Serein.Library.Utils } // 定义动态程序集和模块 - var assemblyName = new AssemblyName("DynamicAssembly"); + /*var assemblyName = new AssemblyName("DynamicAssembly"); var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); - var moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule"); - + var moduleBuilder = AssemblyBuilder.DefineDynamicModule("MainModule"); + */ // 定义动态类型 - var typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public); + var typeBuilder = ModuleBuilder.DefineType(typeName, TypeAttributes.Public); // 为每个属性名和值添加相应的属性到动态类型中 foreach (var kvp in properties) diff --git a/NodeFlow/Model/Node/SingleScriptNode.cs b/NodeFlow/Model/Node/SingleScriptNode.cs index e863c30..c67b524 100644 --- a/NodeFlow/Model/Node/SingleScriptNode.cs +++ b/NodeFlow/Model/Node/SingleScriptNode.cs @@ -35,7 +35,7 @@ namespace Serein.NodeFlow.Model public override bool IsBase => true; private IScriptFlowApi ScriptFlowApi; - private ASTNode mainNode; + private ProgramNode programNode; private SereinScriptInterpreter ScriptInterpreter; private bool IsScriptChanged = false; @@ -167,8 +167,10 @@ namespace Serein.NodeFlow.Model var script = sb.ToString(); var p = new SereinScriptParser(script); //var p = new SereinScriptParser(Script); - mainNode = p.Parse(); // 开始解析 - + programNode = p.Parse(); // 开始解析 + var typeAnalysis = new SereinScriptTypeAnalysis(); + ScriptInterpreter.SetTypeAnalysis(typeAnalysis); + typeAnalysis.AnalysisProgramNode(programNode); } catch (Exception ex) @@ -185,7 +187,8 @@ namespace Serein.NodeFlow.Model /// public override async Task ExecutingAsync(IDynamicContext context, CancellationToken token) { - return await ExecutingAsync(this, context, token); + var result = await ExecutingAsync(this, context, token); + return result; } /// @@ -237,7 +240,8 @@ namespace Serein.NodeFlow.Model if (token.IsCancellationRequested) return null; - var result = await ScriptInterpreter.InterpretAsync(scriptContext, mainNode); // 从入口节点执行 + + var result = await ScriptInterpreter.InterpretAsync(scriptContext, programNode); // 从入口节点执行 envEvent.FlowRunComplete -= onFlowStop; return new FlowResult(this.Guid, context, result); } @@ -253,6 +257,10 @@ namespace Serein.NodeFlow.Model { public static DateTime GetNow() => DateTime.Now; + public static int Add(int Left, int Right) + { + return Left + Right; + } #region 常用的类型转换 public static bool BoolOf(object value) diff --git a/Serein.Script/BinaryOperationEvaluator.cs b/Serein.Script/BinaryOperationEvaluator.cs index 47ae019..5b61220 100644 --- a/Serein.Script/BinaryOperationEvaluator.cs +++ b/Serein.Script/BinaryOperationEvaluator.cs @@ -87,9 +87,11 @@ namespace Serein.Script public static Type EvaluateType(Type leftType, string op, Type rightType) { + if (leftType == null || rightType == null) throw new ArgumentNullException("操作数类型不能为 null"); + // 字符串拼接 if (op == "+" && (leftType == typeof(string) || rightType == typeof(string))) return typeof(string); diff --git a/Serein.Script/IScriptInvokeContext.cs b/Serein.Script/IScriptInvokeContext.cs new file mode 100644 index 0000000..48529bd --- /dev/null +++ b/Serein.Script/IScriptInvokeContext.cs @@ -0,0 +1,51 @@ +using Serein.Library.Api; + +namespace Serein.Script +{ + /// + /// 脚本运行上下文 + /// + public interface IScriptInvokeContext + { + /// + /// 脚本运行的流程上下文,包含了流程上下文和变量等信息 + /// + IDynamicContext FlowContext { get; } + + /// + /// 是否该退出了(由外部发出停止信号) + /// + bool IsReturn { get; } + + /// + /// 是否需要提前返回(用于脚本中提前结束) + /// + bool IsNeedReturn { get; set; } + + /// + /// 是否严格检查 Null 值 (禁止使用 Null) + /// + bool IsCheckNullValue { get; set; } + + /// + /// 获取变量的值 + /// + /// + /// + object GetVarValue(string varName); + + /// + /// 设置变量的值 + /// + /// + /// + /// + bool SetVarValue(string varName, object value); + + /// + /// 结束调用 + /// + /// + void OnExit(); + } +} diff --git a/Serein.Script/Node/AssignmentNode.cs b/Serein.Script/Node/AssignmentNode.cs index d6b3237..b63c353 100644 --- a/Serein.Script/Node/AssignmentNode.cs +++ b/Serein.Script/Node/AssignmentNode.cs @@ -15,13 +15,14 @@ namespace Serein.Script.Node /// /// 变量名称 /// - public string Variable { get; } + //public string Variable { get; } + public ASTNode Target { get; } /// /// 对应的节点 /// public ASTNode Value { get; } - public AssignmentNode(string variable, ASTNode value) => (Variable, Value) = (variable, value); + public AssignmentNode(ASTNode targetObject, ASTNode value) => (Target, Value) = (targetObject, value); } diff --git a/Serein.Script/Node/BinaryOperationNode.cs b/Serein.Script/Node/BinaryOperationNode.cs index 3513de0..902a4bb 100644 --- a/Serein.Script/Node/BinaryOperationNode.cs +++ b/Serein.Script/Node/BinaryOperationNode.cs @@ -12,8 +12,19 @@ namespace Serein.Script.Node public class BinaryOperationNode : ASTNode { + /// + /// 左元 + /// public ASTNode Left { get; } + + /// + /// 操作符(布尔运算符 > 比较运算符 > 加减乘除 ) + /// public string Operator { get; } + + /// + /// 右元 + /// public ASTNode Right { get; } public BinaryOperationNode(ASTNode left, string op, ASTNode right) diff --git a/Serein.Script/Node/ClassTypeDefinitionNode.cs b/Serein.Script/Node/ClassTypeDefinitionNode.cs index b4ff727..878e48f 100644 --- a/Serein.Script/Node/ClassTypeDefinitionNode.cs +++ b/Serein.Script/Node/ClassTypeDefinitionNode.cs @@ -11,8 +11,17 @@ namespace Serein.Script.Node /// public class ClassTypeDefinitionNode : ASTNode { + [Obsolete("此属性已经过时,可能在下一个版本中移除", false)] public bool IsOverlay { get; set; } + + /// + /// 类名称 + /// public string ClassName { get; } + + /// + /// 字段名称及字段类型 + /// public Dictionary Fields { get; } public ClassTypeDefinitionNode(Dictionary fields, string className, bool isOverlay) diff --git a/Serein.Script/Node/CollectionIndexNode.cs b/Serein.Script/Node/CollectionIndexNode.cs index 124e032..4e088c0 100644 --- a/Serein.Script/Node/CollectionIndexNode.cs +++ b/Serein.Script/Node/CollectionIndexNode.cs @@ -11,12 +11,19 @@ namespace Serein.Script.Node /// public class CollectionIndexNode : ASTNode { - public ASTNode TargetValue { get; } - public ASTNode IndexValue { get; } - public CollectionIndexNode(ASTNode collectionValue,ASTNode indexValue) + /// + /// 集合来源 + /// + public ASTNode Collection { get; } + + /// + /// 索引来源 + /// + public ASTNode Index { get; } + public CollectionIndexNode(ASTNode TargetValue,ASTNode indexValue) { - this.TargetValue = collectionValue; - this.IndexValue = indexValue; + this.Collection = TargetValue; + this.Index = indexValue; } } } diff --git a/Serein.Script/Node/FunctionCallNode.cs b/Serein.Script/Node/FunctionCallNode.cs index f7ae335..f4cc620 100644 --- a/Serein.Script/Node/FunctionCallNode.cs +++ b/Serein.Script/Node/FunctionCallNode.cs @@ -11,7 +11,14 @@ namespace Serein.Script.Node /// public class FunctionCallNode : ASTNode { + /// + /// 方法名称 + /// public string FunctionName { get; } + + /// + /// 参数来源 + /// public List Arguments { get; } public FunctionCallNode(string functionName, List arguments) diff --git a/Serein.Script/Node/IdentifierNode.cs b/Serein.Script/Node/IdentifierNode.cs index f2db273..4b1ceb5 100644 --- a/Serein.Script/Node/IdentifierNode.cs +++ b/Serein.Script/Node/IdentifierNode.cs @@ -11,6 +11,9 @@ namespace Serein.Script.Node /// public class IdentifierNode : ASTNode { + /// + /// 定义的名称 + /// public string Name { get; } public IdentifierNode(string name) => Name = name; } diff --git a/Serein.Script/Node/IfNode.cs b/Serein.Script/Node/IfNode.cs index bbf1b2e..b3b9308 100644 --- a/Serein.Script/Node/IfNode.cs +++ b/Serein.Script/Node/IfNode.cs @@ -11,8 +11,19 @@ namespace Serein.Script.Node /// public class IfNode : ASTNode { + /// + /// 条件来源 + /// public ASTNode Condition { get; } + + /// + /// 条件为 true 时所执行的语句 + /// public List TrueBranch { get; } + + /// + /// 条件为 false 时所执行的语句 + /// public List FalseBranch { get; } public IfNode(ASTNode condition, List trueBranch, List falseBranch) => (Condition, TrueBranch, FalseBranch) = (condition, trueBranch, falseBranch); diff --git a/Serein.Script/Node/MemberAccessNode.cs b/Serein.Script/Node/MemberAccessNode.cs index 04cc5a3..85ffdeb 100644 --- a/Serein.Script/Node/MemberAccessNode.cs +++ b/Serein.Script/Node/MemberAccessNode.cs @@ -12,12 +12,12 @@ namespace Serein.Script.Node public class MemberAccessNode : ASTNode { /// - /// 对象token + /// 对象来源 /// public ASTNode Object { get; } /// - /// 成员名称 + /// 对象中要获取的成员的名称 /// public string MemberName { get; } diff --git a/Serein.Script/Node/MemberAssignmentNode.cs b/Serein.Script/Node/MemberAssignmentNode.cs index 7e429a0..9e5adf5 100644 --- a/Serein.Script/Node/MemberAssignmentNode.cs +++ b/Serein.Script/Node/MemberAssignmentNode.cs @@ -12,11 +12,12 @@ namespace Serein.Script.Node public class MemberAssignmentNode : ASTNode { /// - /// 作用的对象 + /// 对象来源 /// public ASTNode Object { get; } + /// - /// 被赋值的成员(属性/字段)名称 + /// 对象中要赋值的成员的名称 /// public string MemberName { get; } /// diff --git a/Serein.Script/Node/MemberFunctionCallNode.cs b/Serein.Script/Node/MemberFunctionCallNode.cs index 0312226..ef21d6a 100644 --- a/Serein.Script/Node/MemberFunctionCallNode.cs +++ b/Serein.Script/Node/MemberFunctionCallNode.cs @@ -12,17 +12,17 @@ namespace Serein.Script.Node public class MemberFunctionCallNode : ASTNode { /// - /// 需要被调用的对象 + /// 对象来源 /// public ASTNode Object { get; } /// - /// 被调用的方法名称 + /// 对象中要调用的方法的名称 /// public string FunctionName { get; } /// - /// 方法参数 + /// 方法参数来源 /// public List Arguments { get; } diff --git a/Serein.Script/Node/ObjectInstantiationNode.cs b/Serein.Script/Node/ObjectInstantiationNode.cs index 6ed41fc..bd5e301 100644 --- a/Serein.Script/Node/ObjectInstantiationNode.cs +++ b/Serein.Script/Node/ObjectInstantiationNode.cs @@ -11,7 +11,14 @@ namespace Serein.Script.Node /// public class ObjectInstantiationNode : ASTNode { + /// + /// 类型名称 + /// public string TypeName { get; } + + /// + /// 构造方法的参数来源 + /// public List Arguments { get; } public ObjectInstantiationNode(string typeName, List arguments) { diff --git a/Serein.Script/Node/ObjectMemberExpressionNode.cs b/Serein.Script/Node/ObjectMemberExpressionNode.cs new file mode 100644 index 0000000..f5033d9 --- /dev/null +++ b/Serein.Script/Node/ObjectMemberExpressionNode.cs @@ -0,0 +1,15 @@ +namespace Serein.Script.Node +{ + public class ObjectMemberExpressionNode : ASTNode + { + /// + /// 对象成员(嵌套获取) + /// + public ASTNode Value { get; } + + public ObjectMemberExpressionNode(ASTNode value) + { + this.Value = value; + } + } +} diff --git a/Serein.Script/Node/ProgramNode.cs b/Serein.Script/Node/ProgramNode.cs index 4624b6e..f56fd2d 100644 --- a/Serein.Script/Node/ProgramNode.cs +++ b/Serein.Script/Node/ProgramNode.cs @@ -11,6 +11,9 @@ namespace Serein.Script.Node /// public class ProgramNode : ASTNode { + /// + /// 程序可执行的语句 + /// public List Statements { get; } public ProgramNode(List statements) diff --git a/Serein.Script/Node/ReturnNode.cs b/Serein.Script/Node/ReturnNode.cs index 259af19..2f49c5a 100644 --- a/Serein.Script/Node/ReturnNode.cs +++ b/Serein.Script/Node/ReturnNode.cs @@ -11,6 +11,9 @@ namespace Serein.Script.Node /// public class ReturnNode : ASTNode { + /// + /// 返回值来源 + /// public ASTNode Value { get; } public ReturnNode(ASTNode returnNode) diff --git a/Serein.Script/Node/WhileNode.cs b/Serein.Script/Node/WhileNode.cs index 4788ba5..18eb4f2 100644 --- a/Serein.Script/Node/WhileNode.cs +++ b/Serein.Script/Node/WhileNode.cs @@ -11,7 +11,14 @@ namespace Serein.Script.Node /// public class WhileNode : ASTNode { + /// + /// 循环条件值来源 + /// public ASTNode Condition { get; } + + /// + /// 循环中语句块 + /// public List Body { get; } public WhileNode(ASTNode condition, List body) => (Condition, Body) = (condition, body); } diff --git a/Serein.Script/NodeInterpreterExtension.cs b/Serein.Script/NodeInterpreterExtension.cs new file mode 100644 index 0000000..654077c --- /dev/null +++ b/Serein.Script/NodeInterpreterExtension.cs @@ -0,0 +1,19 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Serein.Library.Api; +using Serein.Script.Node; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Serein.Script +{ + internal static class NodeInterpreterExtension + { + /*public Task Execution(this MemberAccessNode MemberAccessNode, IScriptFlowApi scriptFlowApi) + { + + }*/ + } +} diff --git a/Serein.Script/ScriptInvokeContext.cs b/Serein.Script/ScriptInvokeContext.cs new file mode 100644 index 0000000..b6c30c0 --- /dev/null +++ b/Serein.Script/ScriptInvokeContext.cs @@ -0,0 +1,79 @@ +using Serein.Library.Api; + +namespace Serein.Script +{ + public class ScriptInvokeContext : IScriptInvokeContext + { + public ScriptInvokeContext(IDynamicContext dynamicContext) + { + FlowContext = dynamicContext; + } + + public IDynamicContext FlowContext{ get; } + + /// + /// 定义的变量 + /// + private Dictionary _variables = new Dictionary(); + + /// + /// 取消令牌源,用于控制脚本的执行 + /// + private CancellationTokenSource _tokenSource = new CancellationTokenSource(); + + /// + /// 是否该退出了 + /// + public bool IsReturn => _tokenSource.IsCancellationRequested; + + /// + /// 是否严格检查 Null 值 (禁止使用 Null) + /// + public bool IsCheckNullValue { get; set; } + + /// + /// 是否需要提前返回(用于脚本中提前结束) + /// + public bool IsNeedReturn { get; set; } + + + object IScriptInvokeContext.GetVarValue(string varName) + { + _variables.TryGetValue(varName, out var value); + return value; + } + + + bool IScriptInvokeContext.SetVarValue(string varName, object? value) + { + if (!_variables.TryAdd(varName, value)) + { + _variables[varName] = value; + } + return true; + } + + + void IScriptInvokeContext.OnExit() + { + // 清理脚本中加载的非托管资源 + foreach (var nodeObj in _variables.Values) + { + if (nodeObj is not null) + { + if (typeof(IDisposable).IsAssignableFrom(nodeObj?.GetType()) && nodeObj is IDisposable disposable) + { + disposable?.Dispose(); + } + } + else + { + + } + } + _tokenSource.Cancel(); + _variables.Clear(); + } + + } +} diff --git a/Serein.Script/SereinSciptException.cs b/Serein.Script/SereinSciptException.cs new file mode 100644 index 0000000..83295b8 --- /dev/null +++ b/Serein.Script/SereinSciptException.cs @@ -0,0 +1,16 @@ +using Serein.Script.Node; + +namespace Serein.Script +{ + public sealed class SereinSciptException : Exception + { + //public ASTNode Node { get; } + public override string Message { get; } + + public SereinSciptException(ASTNode node, string message) + { + //this.Node = node; + Message = $"异常信息 : {message} ,代码在第{node.Row}行: {node.Code.Trim()}"; + } + } +} diff --git a/Serein.Script/SereinScriptInterpreter.cs b/Serein.Script/SereinScriptInterpreter.cs index 1e46d84..a9c2f45 100644 --- a/Serein.Script/SereinScriptInterpreter.cs +++ b/Serein.Script/SereinScriptInterpreter.cs @@ -1,6 +1,5 @@ using Newtonsoft.Json.Linq; using Serein.Library; -using Serein.Library.Api; using Serein.Library.Utils; using Serein.Script.Node; using System.ComponentModel.Design; @@ -11,131 +10,6 @@ using System.Xml.Linq; namespace Serein.Script { - public sealed class SereinSciptException : Exception - { - //public ASTNode Node { get; } - public override string Message { get; } - - public SereinSciptException(ASTNode node, string message) - { - //this.Node = node; - Message = $"异常信息 : {message} ,代码在第{node.Row}行: {node.Code.Trim()}"; - } - } - - - - /// - /// 脚本运行上下文 - /// - public interface IScriptInvokeContext - { - /// - /// 脚本运行的流程上下文,包含了流程上下文和变量等信息 - /// - IDynamicContext FlowContext { get; } - - /// - /// 是否该退出了 - /// - bool IsReturn { get; } - - /// - /// 是否严格检查 Null 值 (禁止使用 Null) - /// - bool IsCheckNullValue { get; set; } - - /// - /// 获取变量的值 - /// - /// - /// - object GetVarValue(string varName); - - /// - /// 设置变量的值 - /// - /// - /// - /// - bool SetVarValue(string varName, object value); - - /// - /// 结束调用 - /// - /// - void OnExit(); - } - - public class ScriptInvokeContext : IScriptInvokeContext - { - public ScriptInvokeContext(IDynamicContext dynamicContext) - { - FlowContext = dynamicContext; - } - - public IDynamicContext FlowContext{ get; } - - /// - /// 定义的变量 - /// - private Dictionary _variables = new Dictionary(); - - /// - /// 取消令牌源,用于控制脚本的执行 - /// - private CancellationTokenSource _tokenSource = new CancellationTokenSource(); - - /// - /// 是否该退出了 - /// - public bool IsReturn => _tokenSource.IsCancellationRequested; - - /// - /// 是否严格检查 Null 值 (禁止使用 Null) - /// - public bool IsCheckNullValue { get; set; } - - - object IScriptInvokeContext.GetVarValue(string varName) - { - _variables.TryGetValue(varName, out var value); - return value; - } - - - bool IScriptInvokeContext.SetVarValue(string varName, object? value) - { - if (!_variables.TryAdd(varName, value)) - { - _variables[varName] = value; - } - return true; - } - - - void IScriptInvokeContext.OnExit() - { - // 清理脚本中加载的非托管资源 - foreach (var nodeObj in _variables.Values) - { - if (nodeObj is not null) - { - if (typeof(IDisposable).IsAssignableFrom(nodeObj?.GetType()) && nodeObj is IDisposable disposable) - { - disposable?.Dispose(); - } - } - else - { - - } - } - _tokenSource.Cancel(); - _variables.Clear(); - } - - } /// /// 脚本解释器,负责解析和执行 Serein 脚本 @@ -147,6 +21,9 @@ namespace Serein.Script /// 挂载的函数 /// private static Dictionary _functionTable = new Dictionary(); + private static Dictionary _functionInfoTable = new Dictionary(); + + public static Dictionary FunctionInfoTable { get { return _functionInfoTable; } } /// /// 挂载的函数调用的对象(用于函数需要实例才能调用的场景) @@ -158,6 +35,12 @@ namespace Serein.Script /// private Dictionary _classDefinition = new Dictionary(); + + /// + /// 类型分析器 + /// + private SereinScriptTypeAnalysis typeAnalysis; + /// /// 挂载静态函数 /// @@ -166,6 +49,7 @@ namespace Serein.Script public static void AddStaticFunction(string functionName, MethodInfo methodInfo) { _functionTable[functionName] = new DelegateDetails(methodInfo); + _functionInfoTable[functionName] = methodInfo; } @@ -216,19 +100,26 @@ namespace Serein.Script } } + /// + /// 设置类型分析器 + /// + /// + public void SetTypeAnalysis(SereinScriptTypeAnalysis typeAnalysis) + { + this.typeAnalysis = typeAnalysis; + } /// /// 入口节点 /// /// /// - private async Task ExecutionProgramNodeAsync(IScriptInvokeContext context, ProgramNode programNode) + private async Task ExecutionProgramNodeAsync(IScriptInvokeContext context,ProgramNode programNode) { // 加载变量 ASTNode statement = null; try { - // 遍历 ProgramNode 中的所有语句并执行它们 for (int index = 0; index < programNode.Statements.Count; index++) { @@ -240,7 +131,11 @@ namespace Serein.Script } else { - await InterpretAsync(context, statement); + var result = await InterpretAsync(context, statement); + if (context.IsNeedReturn) + { + return result; + } } } return null; @@ -268,10 +163,10 @@ namespace Serein.Script return; } - var isOverlay = true; // classTypeDefinitionNode.IsOverlay; + //var isOverlay = true; // classTypeDefinitionNode.IsOverlay; - var type = DynamicObjectHelper.CreateTypeWithProperties(classTypeDefinitionNode.Fields, classTypeDefinitionNode.ClassName, isOverlay); // 覆盖 - classTypeDefinitionNode.IsOverlay = false; // 已经加载过,则不再覆盖 + var type = DynamicObjectHelper.CreateTypeWithProperties(classTypeDefinitionNode.Fields, classTypeDefinitionNode.ClassName); // 覆盖 + //classTypeDefinitionNode.IsOverlay = false; // 已经加载过,则不再覆盖 _classDefinition[classTypeDefinitionNode.ClassName] = type; // 定义对象 } @@ -281,7 +176,7 @@ namespace Serein.Script /// /// /// - private async Task ExecutionIfNodeAsync(IScriptInvokeContext context, IfNode ifNode) + private async Task ExecutionIfNodeAsync(IScriptInvokeContext context, IfNode ifNode) { var result = await EvaluateAsync(context, ifNode.Condition) ?? throw new SereinSciptException(ifNode, $"条件语句返回了 null"); @@ -290,20 +185,30 @@ namespace Serein.Script throw new SereinSciptException(ifNode, "条件语句返回值不为 bool 类型"); } - if (condition) + var branchNodes = condition ? ifNode.TrueBranch : ifNode.FalseBranch; + if(branchNodes is null || branchNodes.Count < 1) { - foreach (var trueNode in ifNode.TrueBranch) - { - await InterpretAsync(context, trueNode); - } + return null; } else { - foreach (var falseNode in ifNode.FalseBranch) + + foreach (var branchNode in branchNodes) { - await InterpretAsync(context,falseNode); + if (branchNode is ReturnNode) // 遇到 Return 语句 提前退出 + { + var reulst = await EvaluateAsync(context, branchNode); + context.IsNeedReturn = true; + return reulst; + } + else + { + await InterpretAsync(context, branchNode); + } } + return null; } + } /// @@ -312,14 +217,14 @@ namespace Serein.Script /// /// /// - private async Task ExectutionWhileNodeAsync(IScriptInvokeContext context, WhileNode whileNode) + private async Task ExectutionWhileNodeAsync(IScriptInvokeContext context, WhileNode whileNode) { while (true) { if (context.IsReturn) // 停止流程 - { - return; + { + throw new SereinSciptException(whileNode, $"while循环已由外部主动停止"); } var result = await EvaluateAsync(context, whileNode.Condition) ?? throw new SereinSciptException(whileNode, $"条件语句返回了 null"); if (result is not bool condition) @@ -330,11 +235,22 @@ namespace Serein.Script { break; } - foreach(var node in whileNode.Body) + foreach(var branchNode in whileNode.Body) { - await InterpretAsync(context, node); + if (branchNode is ReturnNode) // 遇到 Return 语句 提前退出 + { + var reulst = await EvaluateAsync(context, branchNode); + context.IsNeedReturn = true; + return reulst; + } + else + { + await InterpretAsync(context, branchNode); + } + //await InterpretAsync(context, node); } } + return null; } /// @@ -344,13 +260,28 @@ namespace Serein.Script /// private async Task ExecutionAssignmentNodeAsync(IScriptInvokeContext context, AssignmentNode assignmentNode) { - var tmp = await EvaluateAsync(context, assignmentNode.Value); - if(tmp is not null) + if(assignmentNode.Target is IdentifierNode identifierNode) + { + var value = await EvaluateAsync(context, assignmentNode.Value); + if (value is not null) + { + context.SetVarValue(identifierNode.Name, value); + } + } + else { - context.SetVarValue(assignmentNode.Variable, tmp); } + /*var targetObject = await EvaluateAsync(context, assignmentNode.TargetNode); + var value = await EvaluateAsync(context, assignmentNode.Value); + if(value is not null) + { + context.SetVarValue(targetObject, value); + }*/ } + + + private async Task InterpretFunctionCallAsync(IScriptInvokeContext context, FunctionCallNode functionCallNode) { if (functionCallNode.FunctionName.Equals("GetFlowContext", StringComparison.OrdinalIgnoreCase)) @@ -427,16 +358,18 @@ namespace Serein.Script case AssignmentNode assignment: // 出现在 = 右侧的表达式 await ExecutionAssignmentNodeAsync(context, assignment); break; + case ObjectMemberExpressionNode objectMemberExpressionNode: + break; case MemberAssignmentNode memberAssignmentNode: // 设置对象属性 await SetMemberValue(context, memberAssignmentNode); break; case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用 return await CallMemberFunction(context, memberFunctionCallNode); case IfNode ifNode: // 执行 if...else... 语句块 - await ExecutionIfNodeAsync(context, ifNode); + return await ExecutionIfNodeAsync(context, ifNode); break; case WhileNode whileNode: // 循环语句块 - await ExectutionWhileNodeAsync(context, whileNode); + return await ExectutionWhileNodeAsync(context, whileNode); break; case FunctionCallNode functionCallNode: // 方法调用节点 return await InterpretFunctionCallAsync(context, functionCallNode); @@ -517,13 +450,13 @@ namespace Serein.Script case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用 return await CallMemberFunction(context, memberFunctionCallNode); case MemberAccessNode memberAccessNode: // 对象成员访问 - return await GetValue(context, memberAccessNode); + return await GetMemberValue(context, memberAccessNode); case CollectionIndexNode collectionIndexNode: return await GetCollectionValue(context, collectionIndexNode); case ReturnNode returnNode: // 返回内容 return await EvaluateAsync(context, returnNode.Value); // 直接返回响应的内容 - //case ObjectInstantiationNode objectInstantiationNode: // 返回内容 - + case ObjectMemberExpressionNode objectMemberExpressionNode: // 对象链式表达式 + return await EvaluateAsync(context, objectMemberExpressionNode.Value); default: throw new SereinSciptException(node, $"解释器 EvaluateAsync() 未实现{node}节点行为"); } @@ -611,8 +544,24 @@ namespace Serein.Script } else { - var convertedValue = Convert.ChangeType(value, lastProperty.PropertyType); - lastProperty.SetValue(target, convertedValue); + if(value is null) + { + lastProperty.SetValue(target, null); + return; + } + var valueTtpe = value.GetType(); + if (lastProperty.PropertyType.IsAssignableFrom(valueTtpe)) + { + lastProperty.SetValue(target, value); + } + else if (lastProperty.PropertyType.FullName == valueTtpe.FullName) + { + lastProperty.SetValue(target, value); + } + else { + throw new SereinSciptException(memberAssignmentNode, $"对象成员赋值时类型异常:\"{memberAssignmentNode.MemberName}\""); + } + //var convertedValue = Convert.ChangeType(value, ); } } @@ -622,7 +571,7 @@ namespace Serein.Script /// /// /// - public async Task GetValue(IScriptInvokeContext context, MemberAccessNode memberAccessNode) + public async Task GetMemberValue(IScriptInvokeContext context, MemberAccessNode memberAccessNode) { var target = await EvaluateAsync(context, memberAccessNode.Object); var lastMember = memberAccessNode.MemberName; @@ -654,7 +603,7 @@ namespace Serein.Script /// public async Task GetCollectionValue(IScriptInvokeContext context, CollectionIndexNode collectionIndexNode) { - var target = await EvaluateAsync(context, collectionIndexNode.TargetValue); // 获取对象 + var target = await EvaluateAsync(context, collectionIndexNode.Collection); // 获取对象 if (target is null) { throw new ArgumentNullException($"解析{collectionIndexNode}节点时,TargetValue返回空。"); @@ -669,7 +618,7 @@ namespace Serein.Script var method = targetType.GetMethod("get_Item", BindingFlags.Public | BindingFlags.Instance); if (method is not null) { - var key = await EvaluateAsync(context, collectionIndexNode.IndexValue); // 获取索引值; + var key = await EvaluateAsync(context, collectionIndexNode.Index); // 获取索引值; var result = method.Invoke(target, new object[] { key }); return result; } @@ -678,7 +627,7 @@ namespace Serein.Script #region 处理集合对象 else { - var indexValue = await EvaluateAsync(context, collectionIndexNode.IndexValue); // 获取索引值 + var indexValue = await EvaluateAsync(context, collectionIndexNode.Index); // 获取索引值 object? result; if (indexValue is int index) { @@ -702,6 +651,10 @@ namespace Serein.Script result = list[index]; return result; } + else if (target is string chars) + { + return chars[index]; + } else { throw new ArgumentException($"解析{collectionIndexNode}节点时,左值并非有效集合。"); @@ -717,30 +670,58 @@ namespace Serein.Script /// /// 缓存method委托 /// - private Dictionary MethodToDelegateCaches { get; } = new Dictionary(); + private Dictionary MethodToDelegateCaches { get; } = new Dictionary(); public async Task CallMemberFunction(IScriptInvokeContext context, MemberFunctionCallNode memberFunctionCallNode) { var target = await EvaluateAsync(context, memberFunctionCallNode.Object); var lastMember = memberFunctionCallNode.FunctionName; + if(lastMember == "ToUpper") + { - var methodInfo = target?.GetType().GetMethod(lastMember) ?? throw new SereinSciptException(memberFunctionCallNode, $"对象没有方法\"{memberFunctionCallNode.FunctionName}\""); - if(!MethodToDelegateCaches.TryGetValue(methodInfo.Name, out DelegateDetails? delegateDetails)) + } + MethodInfo? methodInfo = null; + if (memberFunctionCallNode.Arguments.Count == 0) + { + + // 查询无参方法 + methodInfo = target?.GetType().GetMethod(lastMember, []) ?? throw new SereinSciptException(memberFunctionCallNode, $"对象没有方法\"{memberFunctionCallNode.FunctionName}\""); + } + else + { + // 获取参数列表的类型 + methodInfo = target?.GetType().GetMethod(lastMember) ?? throw new SereinSciptException(memberFunctionCallNode, $"对象没有方法\"{memberFunctionCallNode.FunctionName}\""); + + } + + /*Type[] paramTypes = new + { + + }*/ + + if (!MethodToDelegateCaches.TryGetValue(methodInfo.MetadataToken, out DelegateDetails? delegateDetails)) { delegateDetails = new DelegateDetails(methodInfo); - MethodToDelegateCaches[methodInfo.Name] = delegateDetails; + MethodToDelegateCaches[methodInfo.MetadataToken] = delegateDetails; } - - - var arguments = new object?[memberFunctionCallNode.Arguments.Count]; - for (int i = 0; i < memberFunctionCallNode.Arguments.Count; i++) + if(memberFunctionCallNode.Arguments.Count == 0) { - ASTNode? arg = memberFunctionCallNode.Arguments[i]; - arguments[i] = await EvaluateAsync(context, arg); // 评估每个参数 + var reuslt = await delegateDetails.InvokeAsync(target, []); + return reuslt; + } + else + { + var arguments = new object?[memberFunctionCallNode.Arguments.Count]; + for (int i = 0; i < memberFunctionCallNode.Arguments.Count; i++) + { + ASTNode? arg = memberFunctionCallNode.Arguments[i]; + arguments[i] = await EvaluateAsync(context, arg); // 评估每个参数 + } + var reuslt = await delegateDetails.InvokeAsync(target, arguments); + return reuslt; } - return await delegateDetails.InvokeAsync(target, arguments); } diff --git a/Serein.Script/SereinScriptLexer.cs b/Serein.Script/SereinScriptLexer.cs index 900deb4..b7f3260 100644 --- a/Serein.Script/SereinScriptLexer.cs +++ b/Serein.Script/SereinScriptLexer.cs @@ -1,4 +1,5 @@ using Newtonsoft.Json.Linq; +using System.Net.Http.Headers; using System.Runtime.CompilerServices; using System.Xml.Linq; using static System.Net.Mime.MediaTypeNames; @@ -137,8 +138,6 @@ namespace Serein.Script private int _index; private int _row ; - private int coreRangeStartIndex = 0; - /// /// 关键字,防止声明为变量 /// @@ -160,16 +159,31 @@ namespace Serein.Script } - internal Token PeekToken() + internal Token PeekToken(int count = 1) { + if (count < 0) throw new Exception() ; int currentIndex = _index; // 保存当前索引 var currentRow = _row; // 保存当前行数 - Token nextToken = NextToken(); // 获取下一个 token + Token nextToken = new Token(); ; + for (var i = 0; i < count; i++) + { + nextToken = NextToken(); // 获取下一个 token + } _index = currentIndex; // 恢复索引到当前位置 _row = currentRow; // 恢复到当前行数 return nextToken; // 返回下一个 token } + /// + /// 根据 token 重置Lexer + /// + /// + public void SetToken(Token token) + { + this._row = token.Row; + this._index = token.StartIndex; + } + internal Token NextToken() { @@ -194,6 +208,7 @@ namespace Serein.Script { return ReadString(); } + if (currentChar == '\'') { diff --git a/Serein.Script/SereinScriptParser.cs b/Serein.Script/SereinScriptParser.cs index a45d6d0..41d2f92 100644 --- a/Serein.Script/SereinScriptParser.cs +++ b/Serein.Script/SereinScriptParser.cs @@ -3,9 +3,11 @@ using Serein.Library; using Serein.Library.Utils; using Serein.Script.Node; using System.Collections.Generic; +using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text; +using System.Xml.Linq; namespace Serein.Script { @@ -30,8 +32,9 @@ namespace Serein.Script /// 解析脚本并返回 AST(抽象语法树)根节点。 /// /// - public ASTNode Parse() + public ProgramNode Parse() { + return Program(); } @@ -43,7 +46,7 @@ namespace Serein.Script /// 解析整个程序,直到遇到文件结尾(EOF)为止。 /// /// - private ASTNode Program() + private ProgramNode Program() { Statements.Clear(); while (_currentToken.Type != TokenType.EOF) @@ -59,7 +62,6 @@ namespace Serein.Script var programNode = new ProgramNode(Statements); programNode.SetTokenInfo(_currentToken); // 程序节点,包含所有解析的语句列表 - SereinScriptTypeAnalysis typeAnalysis = new SereinScriptTypeAnalysis(programNode); return programNode; /*if (astNode is ClassTypeDefinitionNode) @@ -135,6 +137,7 @@ namespace Serein.Script if (_currentToken.Type == TokenType.Null) { // 处理 null 语句 + return BooleanExpression(); return Expression(); } @@ -157,7 +160,254 @@ namespace Serein.Script /// private ASTNode ParseIdentifier() { - + /* + localFunc(); + obj.Func(); + obj.Value = ...; + value = ...; + */ + var backupToken = _currentToken; + var tokenCount = 1; + var int_type = 0; + while (true) + { + var tempToken = _lexer.PeekToken(tokenCount++); + if (tempToken.Type == TokenType.Operator && tempToken.Value == "=") + { + var tempToken2 = _lexer.PeekToken(tokenCount); + if (tempToken2.Type == TokenType.SquareBracketsRight) + { + int_type = 2; // 变量数组赋值 + break; + } + else // if (tempToken2.Type == TokenType.SquareBracketsRight) + { + int_type = 1; // 变量数组赋值 + break; + } + } + if (tempToken.Type == TokenType.Semicolon) + { + var tempToken2 = _lexer.PeekToken(tokenCount); + if(tempToken2.Type == TokenType.ParenthesisRight) + { + int_type = 3; // 方法调用 + break; + } + } + } + if(int_type == 1) // 赋值 MemberAssignmentNode + { + var objectName = _currentToken.Value; + var objectNode = new IdentifierNode(objectName).SetTokenInfo(_currentToken); // 首先定义对象变量节点 + var peekToken = _lexer.PeekToken(); + if(peekToken.Type == TokenType.Operator && peekToken.Value == "=") + { + // 变量赋值 + var valueNode = BooleanExpression(); + var assignmentNode = new AssignmentNode(objectNode, valueNode).SetTokenInfo(_currentToken); + return assignmentNode; + } + else + { + _currentToken = _lexer.NextToken(); // 消耗对象名称 + // 对象成员赋值 + List nodes = new List(); // 表达对象成员路径的节点 + while (true) + { + if (_currentToken.Type == TokenType.Dot) + { + _currentToken = _lexer.NextToken(); // 消耗 "." 获取下一个成员 + if (_currentToken.Type == TokenType.Identifier) + { + var temp2token = _lexer.PeekToken(); + var sourceNode = nodes.Count == 0 ? objectNode : nodes[^1]; + if (temp2token.Type == TokenType.ParenthesisLeft) + { + // 解析方法调用 obj.func() + ASTNode functionNode = ParseMemberFunctionCall(sourceNode).SetTokenInfo(_currentToken); + nodes.Add(functionNode); + } + else if (temp2token.Type == TokenType.SquareBracketsLeft) + { + // 成员数组 obj.dict[key] / obj.array[index] + if (_currentToken.Type == TokenType.Identifier) + { + var memberAccessNode = new MemberAccessNode(sourceNode, _currentToken.Value).SetTokenInfo(_currentToken); + sourceNode = memberAccessNode; + } + var coolectionNode = ParseCollectionIndex(sourceNode).SetTokenInfo(_currentToken); + nodes.Add(coolectionNode); + } + else if (temp2token.Type is TokenType.Dot /* or TokenType.ParenthesisRight*/) + { + // 成员获取 obj.value + var memberAccessNode = new MemberAccessNode(sourceNode, _currentToken.Value).SetTokenInfo(_currentToken); + nodes.Add(memberAccessNode); + } + else if (temp2token.Type == TokenType.Operator && temp2token.Value == "=") + { + // 左值结束, 成员获取 obj.value + /* var memberAccessNode = new MemberAccessNode(sourceNode, _currentToken.Value).SetTokenInfo(_currentToken); + nodes.Add(memberAccessNode);*/ + var memberName = _currentToken.Value; // 成员名称 + _currentToken = _lexer.NextToken(); // 消耗 成员 token + _currentToken = _lexer.NextToken(); // 消耗“=” 等号 + var rightNode = BooleanExpression(); // 判断token + MemberAssignmentNode assignmentNode = new MemberAssignmentNode(sourceNode, memberName, rightNode); + assignmentNode.SetTokenInfo(_currentToken); + + return assignmentNode; // 返回节点 + break; + } + //_lexer.SetToken(peekToken); // 重置lexer + } + } + else + { + _currentToken = _lexer.NextToken(); + } + /*if (_currentToken.Type == TokenType.Operator && _currentToken.Value == "=") + { + // 等号意味着左值语句结束 + break; + }*/ + } + + /* var leftValueNodes = nodes; + List rightValueNode = new List(); // 表达对象成员路径的节点*/ + + + } + + + + } + else if (int_type == 2) // 方法调用 + { + var taretNode = ""; + } + else + { + + } + + return null; + #region MyRegion + /*return null; + var _identifierPeekToken = _lexer.PeekToken(); + if (_identifierPeekToken.Type == TokenType.Operator && _identifierPeekToken.Value == "=") + { + // 如果是操作符 = ,则是直接赋值变量 + var leftValueNode = new IdentifierNode(_currentToken.Value).SetTokenInfo(_currentToken); + var rightValueNode = BooleanExpression(); + return new AssignmentNode(leftValueNode, rightValueNode).SetTokenInfo(_currentToken); + + //return new IdentifierNode(_currentToken.Value).SetTokenInfo(_currentToken); // 获取变量 + } + if (_identifierPeekToken.Type == TokenType.ParenthesisLeft) + { + // 可能是挂载函数调用 + var functionCallNode = ParseFunctionCall(); + return functionCallNode; + } + var objToken = _currentToken; // 对象Token + ASTNode? objectNode = new IdentifierNode(objToken.Value).SetTokenInfo(objToken); // 对象节点 + var identifier = _currentToken.Value; // 标识符字面量 + List nodes = new List(); + while (true) + { + if (_currentToken.Type == TokenType.Dot) + { + _currentToken = _lexer.NextToken(); + if (_currentToken.Type == TokenType.Identifier) + { + var temp2token = _lexer.PeekToken(); + var sourceNode = (nodes.Count == 0 ? objectNode : nodes[^1]); + if(temp2token.Type == TokenType.Operator && temp2token.Value == "=") + { + // 成员获取 obj.value = + var memberAccessNode = new MemberAccessNode(sourceNode, _currentToken.Value).SetTokenInfo(_currentToken); + nodes.Add(memberAccessNode); + //break; + // 赋值行为 + *//*var assignmentNode = ParseAssignment(); + nodes.Add(assignmentNode);*//* + } + else if (temp2token.Type == TokenType.ParenthesisLeft) + { + // 解析方法调用 obj.func() + ASTNode functionNode = ParseMemberFunctionCall(sourceNode).SetTokenInfo(_currentToken); + nodes.Add(functionNode); + } + else if (temp2token.Type == TokenType.SquareBracketsLeft) + { + // 成员数组 obj.dict[key] / obj.array[index] + if (_currentToken.Type == TokenType.Identifier) + { + var memberAccessNode = new MemberAccessNode(sourceNode, _currentToken.Value).SetTokenInfo(_currentToken); + sourceNode = memberAccessNode; + } + var coolectionNode = ParseCollectionIndex(sourceNode).SetTokenInfo(_currentToken); + nodes.Add(coolectionNode); + } + else if (temp2token.Type is TokenType.Dot or TokenType.Semicolon or TokenType.ParenthesisRight ) + { + // 成员获取 obj.value + var memberAccessNode = new MemberAccessNode(sourceNode, _currentToken.Value).SetTokenInfo(_currentToken); + nodes.Add(memberAccessNode); + } + //_lexer.SetToken(peekToken); // 重置lexer + } + } + else + { + _currentToken = _lexer.NextToken(); + } + if (nodes.Count > 0 && _currentToken.Type == TokenType.Operator && _currentToken.Value == "=") + { + _currentToken = _lexer.NextToken(); // 消耗操作符 + // 分号意味着语句结束 + var rightValueNode = BooleanExpression(); + if (nodes.Count == 1) + { + //_currentToken = _lexer.NextToken(); // 右值 + var assignmentNode = new AssignmentNode(nodes[0], rightValueNode); + //var node = nodes[^1]; + return assignmentNode; + } + else + { + var objNode = new ObjectMemberExpressionNode(objectNode, nodes).SetTokenInfo(objToken); + var assignmentNode = new AssignmentNode(objNode, rightValueNode); + return objNode; + } + //AssignmentNode assignmentNode = new AssignmentNode(rightValueNode); + break; + } + if (_currentToken.Type is TokenType.Semicolon) + { + // 分号意味着语句结束 + break; + } + } + if (nodes.Count == 0) + { + return objectNode; + } + if (nodes.Count == 1) + { + var t = new AssignmentNode(objectNode, nodes[^1]); + var node = nodes[^1]; + return node; + } + else + { + var objNode = new ObjectMemberExpressionNode(objectNode, nodes).SetTokenInfo(objToken); + return objNode; + }*/ + #endregion + // 检查标识符后是否跟有左圆括号 var _tempToken = _lexer.PeekToken(); if (_tempToken.Type == TokenType.ParenthesisLeft) @@ -168,6 +418,7 @@ namespace Serein.Script else if (_tempToken.Type == TokenType.Dot) { // 对象成员的获取 + return ParseMemberAccessOrAssignment(); } else if (_tempToken.Type == TokenType.SquareBracketsLeft) @@ -213,7 +464,8 @@ namespace Serein.Script { //_currentToken = _lexer.NextToken(); // 消耗操作符 //_currentToken = _lexer.NextToken(); // 消耗操作符 - valueNode = Expression(); + valueNode = BooleanExpression(); + //valueNode = Expression(); } else if (_tempToken.Type == TokenType.ParenthesisLeft) { @@ -224,9 +476,11 @@ namespace Serein.Script else { // 解析赋值右边的字面量表达式 - valueNode = Expression(); + valueNode = BooleanExpression(); + //valueNode = Expression(); } - return new AssignmentNode(variableName, valueNode).SetTokenInfo(_currentToken); + var variableNode = new IdentifierNode(variableName).SetTokenInfo(_currentToken); + return new AssignmentNode(variableNode, valueNode).SetTokenInfo(_currentToken); } if (_peekToken.Type == TokenType.Dot) { @@ -253,7 +507,7 @@ namespace Serein.Script { _currentToken = _lexer.NextToken(); // Consume "let" - string variable = _currentToken.Value.ToString(); // 变量名称 + string variableName = _currentToken.Value.ToString(); // 变量名称 _currentToken = _lexer.NextToken(); // Consume identifier ASTNode value; AssignmentNode assignmentNode; @@ -261,7 +515,8 @@ namespace Serein.Script { // 定义一个变量,初始值为 null value = new NullNode(); - assignmentNode = new AssignmentNode(variable, value); // 生成node + var variableNode = new IdentifierNode(variableName).SetTokenInfo(_currentToken); + assignmentNode = new AssignmentNode(variableNode, value); // 生成node assignmentNode.SetTokenInfo(_currentToken); // 设置token信息 } else @@ -272,8 +527,10 @@ namespace Serein.Script throw new Exception("Expected '=' after variable name"); _currentToken = _lexer.NextToken(); // 消耗操作符(“=”) var nodeToken = _currentToken; - value = Expression(); // 解析获取赋值表达式 - assignmentNode = new AssignmentNode(variable, value); // 生成node + value = BooleanExpression(); // 解析获取赋值表达式 + //value = Expression(); // 解析获取赋值表达式 + var variableNode = new IdentifierNode(variableName).SetTokenInfo(_currentToken); + assignmentNode = new AssignmentNode(variableNode, value); // 生成node assignmentNode.SetTokenInfo(nodeToken); // 设置token信息 _currentToken = _lexer.NextToken(); // 消耗分号 } @@ -316,7 +573,10 @@ namespace Serein.Script while (_currentToken.Type != TokenType.BraceRight) { // 获取类字段定义 - var fieldType = _currentToken.Value.ToString().ToTypeOfString(); // 获取字段的类型 + var fieldTypeName = _currentToken.Value.ToString(); + var dynamicType = DynamicObjectHelper.GetCacheType(fieldTypeName); + + var fieldType = dynamicType ?? _currentToken.Value.ToString().ToTypeOfString(); // 获取字段的类型 _currentToken = _lexer.NextToken(); // 消耗类型 var fieldName = _currentToken.Value.ToString(); // 获取定义的类名 _currentToken = _lexer.NextToken(); // 消耗字段名称 @@ -334,7 +594,9 @@ namespace Serein.Script } _currentToken = _lexer.NextToken(); // 消耗类型定义 } 括号 - var typeDefinitionCode = _lexer.GetCoreContent(coreStartRangeIndex); // 收集类型定义的代码。(在Statement方法中开始收集的) + var typeDefinitionCode = _lexer.GetCoreContent(coreStartRangeIndex); // 收集类型定义的代码。 + + DynamicObjectHelper.CreateTypeWithProperties(classFields, className, isOverlay); // 解析时缓存类型 var node = new ClassTypeDefinitionNode(classFields, className, isOverlay); _currentToken.Code = typeDefinitionCode; node.SetTokenInfo(_currentToken); @@ -361,7 +623,8 @@ namespace Serein.Script var arguments = new List(); while (_currentToken.Type != TokenType.ParenthesisRight) { - arguments.Add(Expression()); // 获取参数表达式 + //arguments.Add(Expression()); // 获取参数表达式 + arguments.Add(BooleanExpression()); // 获取参数表达式 if (_currentToken.Type == TokenType.Comma) { _currentToken = _lexer.NextToken(); // consume "," @@ -383,17 +646,40 @@ namespace Serein.Script string collectionName = _currentToken.Value.ToString(); //_lexer.NextToken(); // consume "[" - _currentToken = _lexer.NextToken(); // consume identifier + _currentToken = _lexer.NextToken(); // 消耗数组名称 identifier // ParenthesisLeft if (_currentToken.Type != TokenType.SquareBracketsLeft) throw new Exception("Expected '[' after function name"); - _currentToken = _lexer.NextToken(); // consume "[" + _currentToken = _lexer.NextToken(); // 消耗 "[" - ASTNode indexValue = Expression(); // get index value + //ASTNode indexValue = Expression(); // 获取表达数组下标的节点 + ASTNode indexValue = BooleanExpression(); // 获取表达数组下标的节点 - _currentToken = _lexer.NextToken(); // consume "]" - return new CollectionIndexNode(identifierNode,indexValue).SetTokenInfo(_currentToken); + _currentToken = _lexer.NextToken(); // 消耗 "]" + return new CollectionIndexNode(identifierNode, indexValue).SetTokenInfo(_currentToken); + } + + /// + /// 指定对象解析集合索引行为(数组或字典) + /// + /// + /// + public ASTNode ParseCollectionIndex(ASTNode ObjectNode) + { + string collectionName = _currentToken.Value.ToString(); + _currentToken = _lexer.NextToken(); // 消耗数组名称 identifier + // ParenthesisLeft + if (_currentToken.Type != TokenType.SquareBracketsLeft) + throw new Exception("Expected '[' after function name"); + + _currentToken = _lexer.NextToken(); // 消耗 "[" + + //ASTNode indexValue = Expression(); // 获取表达数组下标的节点 + ASTNode indexValue = BooleanExpression(); // 获取表达数组下标的节点 + + _currentToken = _lexer.NextToken(); // 消耗 "]" + return new CollectionIndexNode(ObjectNode, indexValue).SetTokenInfo(_currentToken); } /// @@ -425,7 +711,10 @@ namespace Serein.Script // 成员赋值 obj.Member = xxx; _currentToken = _lexer.NextToken(); // 消耗 "=" _currentToken = _lexer.NextToken(); // 消耗 "=" - var valueNode = Expression(); // 解析右值 + //var valueNode = Expression(); // 解析右值 + var valueNode = BooleanExpression(); // 解析右值 + _currentToken = _lexer.NextToken(); // 消耗 变量 + //_currentToken = _lexer.NextToken(); // 消耗 ; return new MemberAssignmentNode(identifierNode, memberName, valueNode).SetTokenInfo(_peekToken); } else @@ -465,27 +754,28 @@ namespace Serein.Script private ASTNode ParseMemberFunctionCall(ASTNode targetNode) { string functionName = _currentToken.Value.ToString(); // 函数名称 - _currentToken = _lexer.NextToken(); // consume identifier + _currentToken = _lexer.NextToken(); // 消耗函数名称 if (_currentToken.Type != TokenType.ParenthesisLeft) throw new Exception("Expected '(' after function name"); - _currentToken = _lexer.NextToken(); // consume "(" + _currentToken = _lexer.NextToken(); // 消耗 "(" var arguments = new List(); while (_currentToken.Type != TokenType.ParenthesisRight) { // 获取参数表达式 - var arg = Expression(); - _currentToken = _lexer.NextToken(); // consume arg + //var arg = Expression(); + var arg = BooleanExpression(); + _currentToken = _lexer.NextToken(); // 消耗参数 arg arguments.Add(arg); // 添加到参数列表 if (_currentToken.Type == TokenType.Comma) { - _currentToken = _lexer.NextToken(); // consume "," + _currentToken = _lexer.NextToken(); // 消耗参数分隔符 "," } if (_currentToken.Type == TokenType.Semicolon) { - break; // consume ";" + break; // 消耗 ";" } } @@ -510,25 +800,37 @@ namespace Serein.Script _currentToken = _lexer.NextToken(); // consume "(" - var arguments = new List(); bool isBreak = false; - while (_currentToken.Type != TokenType.ParenthesisRight) + var arguments = new List(); + // 获取参数 + while (true)// _currentToken.Type != TokenType.ParenthesisRight { - var arg = Expression(); // 获取参数表达式 - _currentToken = _lexer.NextToken(); // consume arg + //var arg = Expression(); // 获取参数表达式 + var arg = BooleanExpression(); // 获取参数表达式 arguments.Add(arg); if (_currentToken.Type == TokenType.Comma) { - _currentToken = _lexer.NextToken(); // consume "," + _currentToken = _lexer.NextToken(); // 消耗参数分隔符 "," } - if (_currentToken.Type == TokenType.Semicolon) + if (_currentToken.Type == TokenType.ParenthesisRight ) { - isBreak = true; + _currentToken = _lexer.NextToken(); // 消耗方法结束括号 ")" + } + if (_currentToken.Type == TokenType.Semicolon ) + { + //isBreak = true; break; // consume ";" } + /*if (_currentToken.Type == TokenType.Semicolon) // 提前结束 + { + arguments.Add(arg); + isBreak = true; + break; // consume ";" + }*/ + //_currentToken = _lexer.NextToken(); // consume arg } - if(!isBreak) - _currentToken = _lexer.NextToken(); // consume ")" + //if(!isBreak) + // _currentToken = _lexer.NextToken(); // consume ")" //var node = Statements[^1]; @@ -559,7 +861,8 @@ namespace Serein.Script { return new ReturnNode().SetTokenInfo(_currentToken); // 返回空的 ReturnNode } - var resultValue = Expression(); // 获取返回值表达式 + var resultValue = BooleanExpression(); // 获取返回值表达式 + //var resultValue = Expression(); // 获取返回值表达式 _currentToken = _lexer.NextToken(); return new ReturnNode(resultValue).SetTokenInfo(_currentToken); } @@ -574,7 +877,8 @@ namespace Serein.Script { _currentToken = _lexer.NextToken(); // Consume "if" _currentToken = _lexer.NextToken(); // Consume "(" - ASTNode condition = Expression(); + ASTNode condition = BooleanExpression(); + //ASTNode condition = Expression(); _currentToken = _lexer.NextToken(); // Consume ")" // 确保遇到左大括号 { 后进入代码块解析 @@ -590,6 +894,10 @@ namespace Serein.Script while (_currentToken.Type != TokenType.BraceRight && _currentToken.Type != TokenType.EOF) { var astNode = Statement(); // 解析 if 分支中的语句 + while (_currentToken.Type == TokenType.Semicolon) + { + _currentToken = _lexer.NextToken(); + } if (astNode != null) { trueBranch.Add(astNode); // 将 if 分支的语句添加到 trueBranch 中 @@ -608,6 +916,10 @@ namespace Serein.Script while (_currentToken.Type != TokenType.BraceRight && _currentToken.Type != TokenType.EOF) { var astNode = Statement(); // 解析 else 分支中的语句 + while (_currentToken.Type == TokenType.Semicolon) + { + _currentToken = _lexer.NextToken(); + } if (astNode != null) { falseBranch.Add(astNode); // 将 else 分支的语句添加到 falseBranch 中 @@ -633,7 +945,8 @@ namespace Serein.Script { _currentToken = _lexer.NextToken(); // Consume "while" _currentToken = _lexer.NextToken(); // Consume "(" - ASTNode condition = Expression(); + ASTNode condition = BooleanExpression(); + //ASTNode condition = Expression(); _currentToken = _lexer.NextToken(); // Consume ")" _currentToken = _lexer.NextToken(); // Consume "{" List body = new List(); @@ -645,43 +958,131 @@ namespace Serein.Script return new WhileNode(condition, body).SetTokenInfo(_currentToken); } + /* /// + /// 解析表达式。 + /// + /// + private ASTNode Expression() + { + ASTNode left = Term(); + while (_currentToken.Type == TokenType.Operator && ( + _currentToken.Value == "+" || _currentToken.Value == "-")) + { + string op = _currentToken.Value.ToString(); + _currentToken = _lexer.NextToken(); + ASTNode right = Term(); + left = new BinaryOperationNode(left, op, right).SetTokenInfo(_currentToken); + } + while (_currentToken.Type == TokenType.Operator && (_currentToken.Value == "*" || _currentToken.Value == "/")) + { + string op = _currentToken.Value.ToString(); + _currentToken = _lexer.NextToken(); + ASTNode right = Term(); + left = new BinaryOperationNode(left, op, right).SetTokenInfo(_currentToken); + } + return left; + } + + + /// + /// 解析项(Term),比较运算符 + /// + /// + private ASTNode Term() + { + ASTNode left = Factor(); + while (_currentToken.Type == TokenType.Operator && + (_currentToken.Value == "<" || _currentToken.Value == ">" || + _currentToken.Value == "<=" || _currentToken.Value == ">=" || + _currentToken.Value == "==" || _currentToken.Value == "!=")) + { + string op = _currentToken.Value.ToString(); + _currentToken = _lexer.NextToken(); + ASTNode right = Factor(); + left = new BinaryOperationNode(left, op, right).SetTokenInfo(_currentToken); + } + return left; + }*/ + /// - /// 解析表达式。 + /// 顶层布尔表达式 + /// + /// + private ASTNode BooleanExpression() + { + ASTNode left = ComparisonExpression(); + + while (_currentToken.Type == TokenType.Operator && + (_currentToken.Value == "&&" || _currentToken.Value == "||")) + { + string op = _currentToken.Value; + _currentToken = _lexer.NextToken(); + ASTNode right = ComparisonExpression(); + left = new BinaryOperationNode(left, op, right).SetTokenInfo(_currentToken); + } + + return left; + } + + /// + /// 比较表达式(==, !=, <, <=, >, >=) + /// + /// + private ASTNode ComparisonExpression() + { + ASTNode left = Expression(); + + while (_currentToken.Type == TokenType.Operator && + (_currentToken.Value == "==" || _currentToken.Value == "!=" || + _currentToken.Value == "<" || _currentToken.Value == "<=" || + _currentToken.Value == ">" || _currentToken.Value == ">=")) + { + string op = _currentToken.Value; + _currentToken = _lexer.NextToken(); + ASTNode right = Expression(); + left = new BinaryOperationNode(left, op, right).SetTokenInfo(_currentToken); + } + + return left; + } + + /// + /// 加减 /// /// private ASTNode Expression() { ASTNode left = Term(); - while (_currentToken.Type == TokenType.Operator && ( - _currentToken.Value == "+" || _currentToken.Value == "-" || - _currentToken.Value == "*" || _currentToken.Value == "/")) + + while (_currentToken.Type == TokenType.Operator && + (_currentToken.Value == "+" || _currentToken.Value == "-")) { - string op = _currentToken.Value.ToString(); + string op = _currentToken.Value; _currentToken = _lexer.NextToken(); ASTNode right = Term(); left = new BinaryOperationNode(left, op, right).SetTokenInfo(_currentToken); } - return left; + + return left; } - /// - /// 解析项(Term),用于处理加减乘除等运算符。 + /// 乘除 /// /// private ASTNode Term() { ASTNode left = Factor(); + while (_currentToken.Type == TokenType.Operator && - (_currentToken.Value == "<" || _currentToken.Value == ">" || - _currentToken.Value == "<=" || _currentToken.Value == ">=" || - _currentToken.Value == "==" || _currentToken.Value == "!=")) + (_currentToken.Value == "*" || _currentToken.Value == "/")) { - string op = _currentToken.Value.ToString(); + string op = _currentToken.Value; _currentToken = _lexer.NextToken(); ASTNode right = Factor(); left = new BinaryOperationNode(left, op, right).SetTokenInfo(_currentToken); } + return left; } @@ -692,6 +1093,8 @@ namespace Serein.Script /// private ASTNode Factor() { + + #region 返回字面量 if (_currentToken.Type == TokenType.Null) { @@ -757,11 +1160,122 @@ namespace Serein.Script } #endregion + // 标识符节点 + if (_currentToken.Type == TokenType.Identifier) + { + var _identifierPeekToken = _lexer.PeekToken(); + if (_identifierPeekToken.Type is (TokenType.Dot and TokenType.ParenthesisLeft) or TokenType.Semicolon or TokenType.Comma) + { + // 不是 "." 号,也不是 "(" , 或是";",则是获取变量 + var node = new IdentifierNode(_currentToken.Value).SetTokenInfo(_currentToken); // 获取变量 + _currentToken = _lexer.NextToken(); // 消耗变量 + return node; + } + if (_identifierPeekToken.Type == TokenType.ParenthesisLeft) + { + // 可能是挂载函数调用 + var functionCallNode = ParseFunctionCall(); + return functionCallNode; + } + var objToken = _currentToken; // 对象Token + ASTNode? objectNode = new IdentifierNode(objToken.Value).SetTokenInfo(objToken); // 对象节点 + var identifier = _currentToken.Value; // 标识符字面量 + List nodes = new List(); + while (true) + { + if (_currentToken.Type == TokenType.Dot) + { + _currentToken = _lexer.NextToken(); + if (_currentToken.Type == TokenType.Identifier) + { + var temp2token = _lexer.PeekToken(); + var sourceNode = (nodes.Count == 0 ? objectNode : nodes[^1]); + if (temp2token.Type == TokenType.ParenthesisLeft) + { + // 解析方法调用 obj.func() + ASTNode functionNode = ParseMemberFunctionCall(sourceNode).SetTokenInfo(_currentToken); + nodes.Add(functionNode); + } + else if (temp2token.Type == TokenType.SquareBracketsLeft) + { + // 成员数组 obj.dict[key] / obj.array[index] + if (_currentToken.Type == TokenType.Identifier) + { + sourceNode = new MemberAccessNode(sourceNode, _currentToken.Value).SetTokenInfo(_currentToken); + } + var coolectionNode = ParseCollectionIndex(sourceNode).SetTokenInfo(_currentToken); + nodes.Add(coolectionNode); + } + else if (temp2token.Type is TokenType.Operator or TokenType.Dot or TokenType.Semicolon or TokenType.ParenthesisRight) + { + // 成员获取 obj.value + var memberAccessNode = new MemberAccessNode(sourceNode, _currentToken.Value).SetTokenInfo(_currentToken); + nodes.Add(memberAccessNode); + } + //_lexer.SetToken(peekToken); // 重置lexer + } + } + else + { + _currentToken = _lexer.NextToken(); + } + if (_currentToken.Type is TokenType.Operator) + { + // 分号意味着语句结束 + break; + }if (_currentToken.Type is TokenType.Semicolon) + { + // 分号意味着语句结束 + break; + } + } + if (nodes.Count == 0) + { + return objectNode; + } + else + { + var node = nodes[^1]; + var objNode = new ObjectMemberExpressionNode(node).SetTokenInfo(objToken); + return objNode; + } + + + + /* var _identifierPeekToken = _lexer.PeekToken(); + // 该标识符是方法调用 + if (_identifierPeekToken.Type == TokenType.ParenthesisLeft) + { + // 可能是函数调用 + return ParseFunctionCall(); + } + + // 需要从该标识符调用另一个标识符 + if (_identifierPeekToken.Type == TokenType.Dot) + { + // 可能是成员访问或成员赋值 + return ParseMemberAccessOrAssignment(); // 二元操作中获取对象成员 + } + + + // 数组 index; 字典 key obj.Member[xxx]; + if (_identifierPeekToken.Type == TokenType.SquareBracketsLeft) + { + return ParseCollectionIndex(); + } + + _currentToken = _lexer.NextToken(); // 消耗标识符 + return new IdentifierNode(identifier.ToString()).SetTokenInfo(_currentToken);*/ + } + + + // 方法调用 - if (_currentToken.Type == TokenType.ParenthesisLeft) + if (_currentToken.Type == TokenType.ParenthesisLeft) { _currentToken = _lexer.NextToken(); // 消耗 "(" - var expr = Expression(); + var expr = BooleanExpression(); + //var expr = Expression(); if (_currentToken.Type != TokenType.ParenthesisRight) throw new Exception("非预期的符号,预期符号为\")\"。"); _currentToken = _lexer.NextToken(); // 消耗 ")" @@ -775,38 +1289,10 @@ namespace Serein.Script return ParseObjectInstantiation(); } - // 标识符节点 - if (_currentToken.Type == TokenType.Identifier) - { - var identifier = _currentToken.Value; // 标识符字面量 - var _identifierPeekToken = _lexer.PeekToken(); - // 该标识符是方法调用 - if (_identifierPeekToken.Type == TokenType.ParenthesisLeft) - { - // 可能是函数调用 - return ParseFunctionCall(); - } - - // 需要从该标识符调用另一个标识符 - if (_identifierPeekToken.Type == TokenType.Dot) - { - // 可能是成员访问或成员赋值 - return ParseMemberAccessOrAssignment(); // 二元操作中获取对象成员 - } - - - // 数组 index; 字典 key obj.Member[xxx]; - if (_identifierPeekToken.Type == TokenType.SquareBracketsLeft) - { - return ParseCollectionIndex(); - } - - _currentToken = _lexer.NextToken(); // 消耗标识符 - return new IdentifierNode(identifier.ToString()).SetTokenInfo(_currentToken); - } + - throw new Exception("Unexpected factor: " + _currentToken.Value.ToString()); + throw new Exception($"在Expression().Factor()遇到意外的 Token Type ,{_currentToken.Type} {_currentToken.Value} " ); } } diff --git a/Serein.Script/SereinScriptTypeAnalysis.cs b/Serein.Script/SereinScriptTypeAnalysis.cs index 86aeacc..a2ddd8b 100644 --- a/Serein.Script/SereinScriptTypeAnalysis.cs +++ b/Serein.Script/SereinScriptTypeAnalysis.cs @@ -1,51 +1,630 @@ -using Serein.Library.Utils; +using Serein.Library; +using Serein.Library.Utils; using Serein.Script.Node; using Serein.Script.Symbol; using System; using System.Collections.Generic; using System.Linq; using System.Reactive; +using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Xml.Linq; namespace Serein.Script { + + /// + /// 脚本类型分析 + /// public class SereinScriptTypeAnalysis { - private Dictionary SymbolInfos = new Dictionary(); - public SereinScriptTypeAnalysis(ProgramNode programNode) + public SereinScriptTypeAnalysis() + { + + } + + public void AnalysisProgramNode(ProgramNode astNode) + { + NodeSymbolInfos.Clear(); + for (int i = 0; i < astNode.Statements.Count; i++) + { + var node = astNode.Statements[i]; + Analysis(node); + } + var returnNodes = astNode.Statements.Where(node => node is ReturnNode).ToArray(); + if (returnNodes.Length == 0) + { + NodeSymbolInfos[astNode] = typeof(void); // 程序无返回值 + } + else if (returnNodes.Length == 1) + { + var ifNodes = astNode.Statements.Where(node => node is IfNode).ToArray(); + + NodeSymbolInfos[astNode] = NodeSymbolInfos[returnNodes[0]]; // 确定的返回值 + } + else + { + + } + + } + + /// + /// 符号表 + /// + public Dictionary NodeSymbolInfos { get; } = new Dictionary(); + + /// + /// 类型分析、校验 + /// + /// + /// + private void Analysis(ASTNode node) + { + switch (node) + { + case ProgramNode programNode: // 程序开始节点 + break; + case ReturnNode returnNode: // 程序退出节点 + Evaluate(returnNode); // 解析变量定义的类型 + break; + case NullNode nullNode: // null + case CharNode charNode: // char字面量 + case StringNode stringNode: // 字符串字面量 + case BooleanNode booleanNode: // 布尔值字面量 + case NumberIntNode numberIntNode: // int整型数值字面量 + case NumberLongNode numberLongNode: // long整型数值字面量 + case NumberFloatNode numberFloatNode: // float浮点数值字面量 + case NumberDoubleNode numberDoubleNode: // double浮点数值字面量 + Evaluate(node); + break; + case IdentifierNode identifierNode: // 变量定义 + void AnalysisIdentifierNode(IdentifierNode identifierNode) + { + Evaluate(identifierNode); // 解析变量定义的类型 + } + AnalysisIdentifierNode(identifierNode); + break; + case IfNode ifNode: // if语句结构 + void AnalysisIfNode(IfNode ifNode) + { + Evaluate(ifNode); + var conditionType = NodeSymbolInfos[ifNode.Condition]; // 获取条件部分的返回类型 + if (conditionType != typeof(bool?) && conditionType != typeof(bool)) + { + throw new NotImplementedException("if...else...条件返回值不为布尔类型变量"); + } + } + AnalysisIfNode(ifNode); + break; + case WhileNode whileNode: // while语句结构 + void AnalysisWhileNode(WhileNode whileNode) + { + Evaluate(whileNode); + var conditionType = NodeSymbolInfos[whileNode.Condition]; // 获取条件部分的返回类型 + if (conditionType != typeof(bool?) && conditionType != typeof(bool)) + { + throw new NotImplementedException("if...else...条件返回值不为布尔类型变量"); + } + } + AnalysisWhileNode(whileNode); + break; + case AssignmentNode assignmentNode: // 对象赋值语句(let x;默认赋值null。默认类型object) + void AnalysisAssignmentNode(AssignmentNode assignmentNode) + { + Evaluate(assignmentNode); + } + AnalysisAssignmentNode(assignmentNode); + break; + case BinaryOperationNode binaryOperationNode: // 二元运算操作 + void AnalysisBinaryOperationNode(BinaryOperationNode binaryOperationNode) + { + Evaluate(binaryOperationNode); + } + AnalysisBinaryOperationNode(binaryOperationNode); + break; + case CollectionIndexNode collectionIndexNode: // 集合类型操作 + void AnalysisCollectionIndexNode(CollectionIndexNode collectionIndexNode) + { + Evaluate(collectionIndexNode); + /*Analysis(collectionIndexNode.Collection); // 分析集合类型(变量,对象成员) + Analysis(collectionIndexNode.Index); // 分析索引类型 + + var collectionType = NodeSymbolInfos[collectionIndexNode.Collection]; + var indexExprType = NodeSymbolInfos[collectionIndexNode.Index]; + + if (!TryGetIndexerType(collectionType, out var expectedIndexType, out var resultType)) + throw new Exception($"类型 {collectionType} 不支持索引操作"); + + if (!expectedIndexType.IsAssignableFrom(indexExprType)) + throw new Exception($"索引类型不匹配:需要 {expectedIndexType},实际为 {indexExprType}"); + NodeSymbolInfos[collectionIndexNode] = resultType;*/ + } + AnalysisCollectionIndexNode(collectionIndexNode); + break; + case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义 + Evaluate(classTypeDefinitionNode); + break; + case ObjectInstantiationNode objectInstantiationNode: // 类型实例化 + Evaluate(objectInstantiationNode); + break; + case ObjectMemberExpressionNode objectMemberExpressionNode: // 类型表达式(链式调用) + Evaluate(objectMemberExpressionNode); + break; + case MemberAccessNode memberAccessNode: // 对象成员访问 + Evaluate(memberAccessNode); + break; + case MemberAssignmentNode memberAssignmentNode: // 对象成员赋值 + void AnalysisMemberAssignmentNode(MemberAssignmentNode memberAssignmentNode) + { + Evaluate(memberAssignmentNode); + } + AnalysisMemberAssignmentNode(memberAssignmentNode); + break; + case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用 + Evaluate(memberFunctionCallNode); + break; + case FunctionCallNode functionCallNode: // 外部挂载的函数调用 + Evaluate(functionCallNode); + break; + default: // 未定义的节点类型 + break; + } + } + + + /// + /// 类型获取 + /// + /// + /// + /// + /// + private Type Evaluate(ASTNode node) + { + switch (node) + { + case ProgramNode programNode: // 程序开始节点 + NodeSymbolInfos[programNode] = typeof(void); + return typeof(void); + case ReturnNode returnNode: // 程序退出节点 + Type EvaluateReturnNode(ReturnNode returnNode) + { + var resultType = Evaluate(returnNode.Value); + NodeSymbolInfos[returnNode.Value] = resultType; + NodeSymbolInfos[returnNode] = resultType; + return resultType; + } + return EvaluateReturnNode(returnNode); + case NullNode nullNode: // null + NodeSymbolInfos[nullNode] = typeof(object); + return typeof(object); + case CharNode charNode: // char字面量 + NodeSymbolInfos[charNode] = typeof(char); + return typeof(char); + case StringNode stringNode: // 字符串字面量 + NodeSymbolInfos[stringNode] = typeof(string); + return typeof(string); + case BooleanNode booleanNode: // 布尔值字面量 + NodeSymbolInfos[booleanNode] = typeof(bool); + return typeof(bool); + case NumberIntNode numberIntNode: // int整型数值字面量 + NodeSymbolInfos[numberIntNode] = typeof(int); + return typeof(int); + case NumberLongNode numberLongNode: // long整型数值字面量 + NodeSymbolInfos[numberLongNode] = typeof(long); + return typeof(long); + case NumberFloatNode numberFloatNode: // float浮点数值字面量 + NodeSymbolInfos[numberFloatNode] = typeof(float); + return typeof(float); + case NumberDoubleNode numberDoubleNode: // double浮点数值字面量 + NodeSymbolInfos[numberDoubleNode] = typeof(double); + return typeof(double); + case IdentifierNode identifierNode: // 变量定义 + Type EvaluateIdentifierNode(IdentifierNode identifierNode) + { + var cacheNode = NodeSymbolInfos.Keys.FirstOrDefault(n => n is IdentifierNode idNode && idNode.Name == identifierNode.Name); + Type type = cacheNode is null ? typeof(object) : NodeSymbolInfos[cacheNode]; + NodeSymbolInfos[identifierNode] = type; + return type; + } + return EvaluateIdentifierNode(identifierNode); + case IfNode ifNode: // if语句结构 + Type EvaluateIfNode(IfNode ifNode) + { + var conditionType = Evaluate(ifNode.Condition); // 获取条件语句部分的返回类型 + NodeSymbolInfos[ifNode.Condition] = conditionType; + if (conditionType == typeof(bool?) || conditionType == typeof(bool)) + { + foreach (var item in ifNode.TrueBranch) + { + var itemType = Evaluate(item); // 解析真分支的语句块 + NodeSymbolInfos[item] = itemType; + } + foreach (var item in ifNode.FalseBranch) + { + var itemType = Evaluate(item); // 解析假分支的语句块 + NodeSymbolInfos[item] = itemType; + } + NodeSymbolInfos[ifNode] = typeof(void); + return typeof(void); // if语句不产生类型 + } + else + { + throw new NotImplementedException("if...else...条件返回值不为布尔类型变量"); + } + } + return EvaluateIfNode(ifNode); + case WhileNode whileNode: // while语句结构 + Type EvaluateWhileNode(WhileNode whileNode) + { + var conditionType = Evaluate(whileNode.Condition); // 获取条件语句部分的返回类型 + NodeSymbolInfos[whileNode.Condition] = conditionType; + if (conditionType == typeof(bool?) || conditionType == typeof(bool)) + { + foreach (var item in whileNode.Body) + { + var itemType = Evaluate(item); // 解析真分支的语句块 + NodeSymbolInfos[item] = itemType; + } + NodeSymbolInfos[whileNode] = typeof(void); // while流程不产生类型 + return typeof(void); // if语句不产生类型 + } + else + { + throw new NotImplementedException("if...else...条件返回值不为布尔类型变量"); + } + } + return EvaluateWhileNode(whileNode); + case AssignmentNode assignmentNode: + // 对象赋值语句(let x;默认赋值null。默认类型object) + Type EvaluateAssignmentNode(AssignmentNode assignmentNode) + { + var targetType = Evaluate(assignmentNode.Target); + var valueType = Evaluate (assignmentNode.Value); + if (!targetType.IsAssignableFrom(valueType)) + throw new Exception($"索引类型不匹配:需要 {targetType},实际为 {valueType}"); + NodeSymbolInfos[assignmentNode.Value] = valueType; + NodeSymbolInfos[assignmentNode.Target] = valueType; + NodeSymbolInfos[assignmentNode] = typeof(void); // 赋值语句不产生类型 + return targetType; + } + return EvaluateAssignmentNode(assignmentNode); + case BinaryOperationNode binaryOperationNode: // 二元运算操作 + Type EvaluateBinaryOperationNode(BinaryOperationNode binaryOperationNode) + { + var leftType = Evaluate(binaryOperationNode.Left); // 递归判断左值类型 + var rightType = Evaluate(binaryOperationNode.Right); // 递归判断右值类型 + var op = binaryOperationNode.Operator; + var resultType = BinaryOperationEvaluator.EvaluateType(leftType, op, rightType); + NodeSymbolInfos[binaryOperationNode.Left] = leftType; + NodeSymbolInfos[binaryOperationNode.Right] = rightType; + NodeSymbolInfos[binaryOperationNode] = resultType; + return resultType; + } + return EvaluateBinaryOperationNode(binaryOperationNode); + case CollectionIndexNode collectionIndexNode: // 集合类型操作,获取集合操作后返回的类型 + Type EvaluateCollectionIndexNode(CollectionIndexNode collectionIndexNode) + { + var collectionType = Evaluate(collectionIndexNode.Collection); // 分析集合类型(变量,对象成员) + var indexExprType = Evaluate(collectionIndexNode.Index); // 分析索引类型 + if (!TryGetIndexerType(collectionType, out var expectedIndexType, out var resultType)) + throw new Exception($"类型 {collectionType} 不支持索引操作"); + + if (!expectedIndexType.IsAssignableFrom(indexExprType)) + throw new Exception($"索引类型不匹配:需要 {expectedIndexType},实际为 {indexExprType}"); + NodeSymbolInfos[collectionIndexNode.Collection] = collectionType; + NodeSymbolInfos[collectionIndexNode.Index] = indexExprType; + NodeSymbolInfos[collectionIndexNode] = resultType; + return resultType; + } + return EvaluateCollectionIndexNode(collectionIndexNode); + case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义 + Type EvaluateClassTypeDefinitionNode(ClassTypeDefinitionNode classTypeDefinitionNode) + { + var classType = DynamicObjectHelper.GetCacheType(classTypeDefinitionNode.ClassName); + if (classType is null) + classType = DynamicObjectHelper.CreateTypeWithProperties(classTypeDefinitionNode.Fields, classTypeDefinitionNode.ClassName); + NodeSymbolInfos[classTypeDefinitionNode] = classType; + return classType; + } + return EvaluateClassTypeDefinitionNode(classTypeDefinitionNode); + case ObjectInstantiationNode objectInstantiationNode: // 类型实例化 + Type EvaluateObjectInstantiationNode(ObjectInstantiationNode objectInstantiationNode) + { + Type? resultType = null; + try + { + resultType = Type.GetType(objectInstantiationNode.TypeName); // 从命名空间查询类型 + } + finally + { + if (resultType is null) + { + resultType = DynamicObjectHelper.GetCacheType(objectInstantiationNode.TypeName); // 从自定义类型查询类型 + } + } + NodeSymbolInfos[objectInstantiationNode] = resultType; + return resultType; + } + return EvaluateObjectInstantiationNode(objectInstantiationNode); + case ObjectMemberExpressionNode objectMemberExpressionNode: // 类型表达式(链式调用) + Type EvaluateObjectMemberExpressionNode(ObjectMemberExpressionNode objectMemberExpressionNode) + { + // 1. 对象成员获取 MemberAccessNode + // 2. 对象方法调用 MemberFunctionCallNode + // 3. 对象集合成员获取 CollectionIndexNode + Type? resultType = Evaluate(objectMemberExpressionNode.Value); + NodeSymbolInfos[objectMemberExpressionNode.Value] = resultType; + NodeSymbolInfos[objectMemberExpressionNode] = resultType; + return resultType; + } + return EvaluateObjectMemberExpressionNode(objectMemberExpressionNode); + case MemberAccessNode memberAccessNode: // 对象成员访问 + Type EvaluateMemberAccessNode(MemberAccessNode memberAccessNode) + { + var objectType = Evaluate(memberAccessNode.Object); + var property = objectType.GetProperty(memberAccessNode.MemberName); + if (property is null) + throw new Exception($"类型 {objectType} 没有成员 {memberAccessNode.MemberName}"); + NodeSymbolInfos[memberAccessNode.Object] = objectType; + NodeSymbolInfos[memberAccessNode] = property.PropertyType; + return property.PropertyType; + } + return EvaluateMemberAccessNode(memberAccessNode); + case MemberAssignmentNode memberAssignmentNode: // 对象成员赋值 + Type EvaluateMemberAssignmentNode(MemberAssignmentNode memberAssignmentNode) + { + var objectType = Evaluate(memberAssignmentNode.Object); + var property = objectType.GetProperty(memberAssignmentNode.MemberName); + if(property is null) + throw new Exception($"类型异常:类型 {objectType} 没有成员 {memberAssignmentNode.MemberName}"); + var propertyType = property.PropertyType; + var valueType = Evaluate(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 EvaluateMemberAssignmentNode(memberAssignmentNode); + case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用 + Type EvaluateMemberFunctionCallNode(MemberFunctionCallNode memberFunctionCallNode) + { + var objectType = Evaluate(memberFunctionCallNode.Object); + var types = memberFunctionCallNode.Arguments.Select(arg => Evaluate(arg)).ToArray(); + var methodInfo = objectType.GetMethod(memberFunctionCallNode.FunctionName, types); + if (methodInfo is null) + throw new Exception($"类型 {objectType} 没有方法 {memberFunctionCallNode.FunctionName}"); + for (int index = 0; index < memberFunctionCallNode.Arguments.Count; index++) + { + ASTNode argNode = memberFunctionCallNode.Arguments[index]; + Type argType = types[index]; + NodeSymbolInfos[argNode] = argType; + } + NodeSymbolInfos[memberFunctionCallNode.Object] = objectType; + NodeSymbolInfos[memberFunctionCallNode] = methodInfo.ReturnType; + return methodInfo.ReturnType; + } + return EvaluateMemberFunctionCallNode(memberFunctionCallNode); + case FunctionCallNode functionCallNode: // 外部挂载的函数调用 + Type EvaluateFunctionCallNode(FunctionCallNode functionCallNode) + { + if(!SereinScriptInterpreter.FunctionInfoTable.TryGetValue(functionCallNode.FunctionName, out var methodInfo)) + { + throw new Exception($"脚本没有挂载方法 {functionCallNode.FunctionName}"); + } + var types = functionCallNode.Arguments.Select(arg => Evaluate(arg)).ToArray(); + for (int index = 0; index < functionCallNode.Arguments.Count; index++) + { + ASTNode argNode = functionCallNode.Arguments[index]; + Type argType = types[index]; + NodeSymbolInfos[argNode] = argType; + } + NodeSymbolInfos[functionCallNode] = methodInfo.ReturnType; + return methodInfo.ReturnType; + } + return EvaluateFunctionCallNode(functionCallNode); + default: // 未定义的节点类型 + break; + } + throw new NotImplementedException(); + } + + + + + + + + + + + private void Analysis2(ASTNode node) + { + switch (node) + { + case ProgramNode programNode: // 程序开始节点 + break; + case ReturnNode returnNode: // 程序退出节点 + break; + case NullNode nullNode: // null + break; + case CharNode charNode: // char字面量 + break; + case StringNode stringNode: // 字符串字面量 + break; + case BooleanNode booleanNode: // 布尔值字面量 + break; + case NumberIntNode numberIntNode: // int整型数值字面量 + break; + case NumberLongNode numberLongNode: // long整型数值字面量 + break; + case NumberFloatNode numberFloatNode: // float浮点数值字面量 + break; + case NumberDoubleNode numberDoubleNode: // double浮点数值字面量 + break; + case IdentifierNode identifierNode: // 变量定义 + break; + case IfNode ifNode: // if语句结构 + break; + case WhileNode whileNode: // while语句结构 + break; + case AssignmentNode assignmentNode: // 对象赋值语句(let x;默认赋值null。默认类型object) + break; + case BinaryOperationNode binaryOperationNode: // 二元运算操作 + break; + case CollectionIndexNode collectionIndexNode: // 集合类型操作 + break; + case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义 + break; + case ObjectInstantiationNode objectInstantiationNode: // 类型实例化 + break; + case ObjectMemberExpressionNode objectMemberExpressionNode: // 类型表达式(链式调用) + break; + case MemberAccessNode memberAccessNode: // 对象成员访问 + break; + case MemberAssignmentNode memberAssignmentNode: // 对象成员赋值 + break; + case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用 + break; + case FunctionCallNode functionCallNode: // 外部挂载的函数调用 + break; + default: // 未定义的节点类型 + break; + } + } + + + /// + /// 获取某个集合类型支持的索引参数类型 + /// + /// 集合类型 + /// 索引 + /// 获取到的类型 + /// + public static bool TryGetIndexerType(Type collectionType, out Type indexType, out Type resultType) + { + indexType = null!; + resultType = null!; + + // 检查是否是数组 + if (collectionType.IsArray) + { + indexType = typeof(int); + resultType = collectionType.GetElementType()!; + return true; + } + + // 检查是否实现 IDictionary + var dictInterface = collectionType + .GetInterfaces() + .FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IDictionary<,>)); + + if (dictInterface != null) + { + var args = dictInterface.GetGenericArguments(); + indexType = args[0]; // Key + resultType = args[1]; // Value + return true; + } + + // 检查是否实现 IList + var listInterface = collectionType + .GetInterfaces() + .FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IList<>)); + + if (listInterface != null) + { + indexType = typeof(int); + resultType = listInterface.GetGenericArguments()[0]; + return true; + } + + // 检查是否有索引器属性 + var indexer = collectionType + .GetDefaultMembers() + .OfType() + .FirstOrDefault(p => + { + var args = p.GetIndexParameters(); + return args.Length == 1; + }); + + if (indexer != null) + { + var param = indexer.GetIndexParameters()[0]; + indexType = param.ParameterType; + resultType = indexer.PropertyType; + return true; + } + + return false; + } + + + + + + + + + + #region 初始化符号表 + /// + /// 符号表 + /// + public Dictionary SymbolInfos { get; } = new Dictionary(); + + + /* public SereinScriptTypeAnalysis(ProgramNode programNode) { SymbolInfos.Clear(); // 清空符号表 + + // 初始化符号表 foreach (ASTNode astNode in programNode.Statements) { var type = Trace(astNode); if (type is null) continue; var info = Analyse(astNode, type); - if(info != null) + if (info != null) { SymbolInfos[info.Name] = info; } - /*if(astNode is AssignmentNode assignmentNode) - { - var name = assignmentNode.Variable; - var node = assignmentNode.Value; - var type = Analyse(node); - if(type is null) - { - continue; - } - var symbolInfo = new SymbolInfo - { - Type = type, - Node = node, - Name = name, - }; - SymbolInfos[name] = symbolInfo; - }*/ + } + + // 类型分析 + foreach (ASTNode astNode in programNode.Statements) + { } } +*/ + + private Type? GetTypeOnMemberFunctionCallNode(ASTNode objectNode) + { + Type objectType = null; + if (objectNode is IdentifierNode identifierNode) + { + if (SymbolInfos.TryGetValue(identifierNode.Name, out var symbolInfo)) + { + objectType = symbolInfo.Type; + } + } + return objectType; + } + + private Type? GetMethodReturnType(Type type, string methodName) + { + if (type is null) return null; + var methodInfos = type.GetMethods(); + var methodInfo = methodInfos.FirstOrDefault(md => md.Name == methodName); + var returnType = methodInfo?.ReturnType; + return returnType; + } + /// /// 追踪类型 @@ -71,12 +650,27 @@ namespace Serein.Script case CharNode charNode: // char return typeof(char); case IdentifierNode identifierNode: // 定义变量 - return typeof(object); + if(SymbolInfos.TryGetValue(identifierNode.Name, out var varSymbolInfo)) + { + return varSymbolInfo.Type; // 返回定义的类型 + } + return typeof(object); // 默认为 object case AssignmentNode assignmentNode: // 赋值行为 - var type = Trace(assignmentNode.Value); - return type; - //throw new SereinSciptException(identifierNode, "尝试使用值为null的变量"); - //throw new SereinSciptException(identifierNode, "尝试使用未声明的变量"); + var targetType = Trace(assignmentNode.Target); + var valueType = Trace(assignmentNode.Value); + if (targetType.IsAssignableFrom(valueType)) + { + if(assignmentNode.Target is IdentifierNode identifierNode + && !SymbolInfos.ContainsKey(identifierNode.Name)) + { + return valueType; + } + return targetType; + } + else + { + throw new Exception("无法转换类型"); + } case BinaryOperationNode binOpNode: // 递归计算二元操作 var leftType = Trace(binOpNode.Left); var op = binOpNode.Operator; @@ -84,18 +678,29 @@ namespace Serein.Script var resultType = BinaryOperationEvaluator.EvaluateType(leftType, op, rightType); return resultType; case ClassTypeDefinitionNode classTypeDefinitionNode: - var definitionType = DynamicObjectHelper.CreateTypeWithProperties(classTypeDefinitionNode.Fields, classTypeDefinitionNode.ClassName, true); + var definitionType = DynamicObjectHelper.CreateTypeWithProperties(classTypeDefinitionNode.Fields, classTypeDefinitionNode.ClassName); return definitionType; case ObjectInstantiationNode objectInstantiationNode: // 创建对象 - var typeName = objectInstantiationNode.TypeName; var objectType = Type.GetType(typeName); objectType ??= DynamicObjectHelper.GetCacheType(typeName); return objectType; case FunctionCallNode callNode: // 调用方法 return null; + case MemberAssignmentNode memberAssignmentNode: + var leftValueType = Trace(memberAssignmentNode.Object); + var propertyType = leftValueType.GetProperty(memberAssignmentNode.MemberName)?.PropertyType; + var rightValueType = Trace(memberAssignmentNode.Value); + if (propertyType is not null && !propertyType.IsAssignableFrom(rightValueType)) + { + throw new Exception("无法转换类型"); + } + break; case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用 - return null; + var objectNode = memberFunctionCallNode.Object; + var objType = GetTypeOnMemberFunctionCallNode(objectNode); + var methodName = memberFunctionCallNode.FunctionName; + return GetMethodReturnType(objType, methodName); case MemberAccessNode memberAccessNode: // 对象成员访问 var memberType = memberAccessNode.MemberName; return null; @@ -110,7 +715,7 @@ namespace Serein.Script return null; } - + private SymbolInfo Analyse(ASTNode node, Type type) { @@ -128,20 +733,32 @@ namespace Serein.Script Type = type, }; case AssignmentNode assignmentNode: // 赋值行为 - return new SymbolInfo + if(assignmentNode.Target is IdentifierNode identifierNode1) { - Name = assignmentNode.Variable, - Node = node, - Type = type, - }; + return new SymbolInfo + { + Name = identifierNode1.Name, + Node = node, + Type = type, + }; + } + break; + case BinaryOperationNode binOpNode: // 递归计算二元操作 + break; //case ClassTypeDefinitionNode classTypeDefinitionNode case ObjectInstantiationNode objectInstantiationNode: // 创建对象 + break; case FunctionCallNode callNode: // 调用方法 + break; case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用 + break; case MemberAccessNode memberAccessNode: // 对象成员访问 + break; case CollectionIndexNode collectionIndexNode: + break; case ReturnNode returnNode: // 返回内容 + break; default: break; //throw new SereinSciptException(node, $"解释器 EvaluateAsync() 未实现{node}节点行为"); @@ -150,24 +767,43 @@ namespace Serein.Script return null; } - /* - case NullNode nullNode: // 返回null - case BooleanNode booleanNode: // 返回布尔 - case NumberIntNode numberNode: // 数值 - case StringNode stringNode: // 字符串 - case CharNode charNode: // char - case IdentifierNode identifierNode: // 定义变量 - case AssignmentNode assignmentNode: // 赋值行为 - case BinaryOperationNode binOpNode: // 递归计算二元操作 - case ObjectInstantiationNode objectInstantiationNode: // 创建对象 - case FunctionCallNode callNode: // 调用方法 - case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用 - case MemberAccessNode memberAccessNode: // 对象成员访问 - case CollectionIndexNode collectionIndexNode: - case ReturnNode returnNode: // 返回内容 - default: - break; - */ + #endregion + } } + + + + + + + +/* + case NullNode nullNode: // 返回null + case BooleanNode booleanNode: // 返回布尔 + case NumberIntNode numberNode: // 数值 + case StringNode stringNode: // 字符串 + case CharNode charNode: // char + case IdentifierNode identifierNode: // 定义变量 + case AssignmentNode assignmentNode: // 赋值行为 + case BinaryOperationNode binOpNode: // 递归计算二元操作 + case ObjectInstantiationNode objectInstantiationNode: // 创建对象 + case FunctionCallNode callNode: // 调用方法 + case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用 + case MemberAccessNode memberAccessNode: // 对象成员访问 + case CollectionIndexNode collectionIndexNode: + case ReturnNode returnNode: // 返回内容 + default: + break; +*/ +/* if (SymbolInfos.TryGetValue(varName, out var symbolInfo)) + { + var state = symbolInfo.Type.IsAssignableFrom(type); + if (!state) + { + // 错误:变量[{varName}]赋值异常,[{type.FullName}]无法转换为[{symbolInfo.Type.FullName}] + //SereinEnv.WriteLine(InfoType.ERROR, $"[{type.FullName}]无法转化为[{symbolInfo.Type.FullName}]。源代码:{assignmentNode.Code.Replace(Environment.NewLine,"")} [行{assignmentNode.Row}]"); + SereinEnv.WriteLine(InfoType.ERROR, $"类型异常:无法赋值变量[{varName}],因为[{type.FullName}]无法转化为[{symbolInfo.Type.FullName}]。在[行{assignmentNode.Row}]:{assignmentNode.Code}"); + } + }*/ diff --git a/Serein.Script/Symbol/SymbolInfo.cs b/Serein.Script/Symbol/SymbolInfo.cs index 81338c3..668cbab 100644 --- a/Serein.Script/Symbol/SymbolInfo.cs +++ b/Serein.Script/Symbol/SymbolInfo.cs @@ -17,7 +17,7 @@ namespace Serein.Script.Symbol /// /// 符号信息 /// - internal class SymbolInfo + public class SymbolInfo { /// /// 符号名称