为Serein.Script增加类型分析,增加了更加详细的Number类型节点,优化了对象节点的链式表达式,修复了Lexer分析词法时,部分Token代码属性错误的问题。

This commit is contained in:
fengjiayi
2025-07-11 20:52:21 +08:00
parent 70f674ca1b
commit ec764c5675
27 changed files with 1724 additions and 334 deletions

View File

@@ -14,7 +14,17 @@ namespace Serein.Library.Utils
public class DynamicObjectHelper
{
// 类型缓存,键为类型的唯一名称(可以根据实际需求调整生成方式)
static Dictionary<string, Type> typeCache = new Dictionary<string, Type>();
private static Dictionary<string, Type> typeCache = new Dictionary<string, Type>();
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");
}
/// <summary>
/// 获取运行时创建过的类型
@@ -82,6 +92,8 @@ namespace Serein.Library.Utils
}
}
/// <summary>
/// 创建具有属性的类型
/// </summary>
@@ -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)

View File

@@ -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
/// <returns></returns>
public override async Task<FlowResult> ExecutingAsync(IDynamicContext context, CancellationToken token)
{
return await ExecutingAsync(this, context, token);
var result = await ExecutingAsync(this, context, token);
return result;
}
/// <summary>
@@ -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)

View File

@@ -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);

View File

@@ -0,0 +1,51 @@
using Serein.Library.Api;
namespace Serein.Script
{
/// <summary>
/// 脚本运行上下文
/// </summary>
public interface IScriptInvokeContext
{
/// <summary>
/// 脚本运行的流程上下文,包含了流程上下文和变量等信息
/// </summary>
IDynamicContext FlowContext { get; }
/// <summary>
/// 是否该退出了(由外部发出停止信号)
/// </summary>
bool IsReturn { get; }
/// <summary>
/// 是否需要提前返回(用于脚本中提前结束)
/// </summary>
bool IsNeedReturn { get; set; }
/// <summary>
/// 是否严格检查 Null 值 (禁止使用 Null
/// </summary>
bool IsCheckNullValue { get; set; }
/// <summary>
/// 获取变量的值
/// </summary>
/// <param name="varName"></param>
/// <returns></returns>
object GetVarValue(string varName);
/// <summary>
/// 设置变量的值
/// </summary>
/// <param name="varName"></param>
/// <param name="value"></param>
/// <returns></returns>
bool SetVarValue(string varName, object value);
/// <summary>
/// 结束调用
/// </summary>
/// <returns></returns>
void OnExit();
}
}

View File

@@ -15,13 +15,14 @@ namespace Serein.Script.Node
/// <summary>
/// 变量名称
/// </summary>
public string Variable { get; }
//public string Variable { get; }
public ASTNode Target { get; }
/// <summary>
/// 对应的节点
/// </summary>
public ASTNode Value { get; }
public AssignmentNode(string variable, ASTNode value) => (Variable, Value) = (variable, value);
public AssignmentNode(ASTNode targetObject, ASTNode value) => (Target, Value) = (targetObject, value);
}

View File

@@ -12,8 +12,19 @@ namespace Serein.Script.Node
public class BinaryOperationNode : ASTNode
{
/// <summary>
/// 左元
/// </summary>
public ASTNode Left { get; }
/// <summary>
/// 操作符(布尔运算符 > 比较运算符 > 加减乘除
/// </summary>
public string Operator { get; }
/// <summary>
/// 右元
/// </summary>
public ASTNode Right { get; }
public BinaryOperationNode(ASTNode left, string op, ASTNode right)

View File

@@ -11,8 +11,17 @@ namespace Serein.Script.Node
/// </summary>
public class ClassTypeDefinitionNode : ASTNode
{
[Obsolete("此属性已经过时,可能在下一个版本中移除", false)]
public bool IsOverlay { get; set; }
/// <summary>
/// 类名称
/// </summary>
public string ClassName { get; }
/// <summary>
/// 字段名称及字段类型
/// </summary>
public Dictionary<string, Type> Fields { get; }
public ClassTypeDefinitionNode(Dictionary<string, Type> fields, string className, bool isOverlay)

View File

@@ -11,12 +11,19 @@ namespace Serein.Script.Node
/// </summary>
public class CollectionIndexNode : ASTNode
{
public ASTNode TargetValue { get; }
public ASTNode IndexValue { get; }
public CollectionIndexNode(ASTNode collectionValue,ASTNode indexValue)
/// <summary>
/// 集合来源
/// </summary>
public ASTNode Collection { get; }
/// <summary>
/// 索引来源
/// </summary>
public ASTNode Index { get; }
public CollectionIndexNode(ASTNode TargetValue,ASTNode indexValue)
{
this.TargetValue = collectionValue;
this.IndexValue = indexValue;
this.Collection = TargetValue;
this.Index = indexValue;
}
}
}

View File

@@ -11,7 +11,14 @@ namespace Serein.Script.Node
/// </summary>
public class FunctionCallNode : ASTNode
{
/// <summary>
/// 方法名称
/// </summary>
public string FunctionName { get; }
/// <summary>
/// 参数来源
/// </summary>
public List<ASTNode> Arguments { get; }
public FunctionCallNode(string functionName, List<ASTNode> arguments)

View File

@@ -11,6 +11,9 @@ namespace Serein.Script.Node
/// </summary>
public class IdentifierNode : ASTNode
{
/// <summary>
/// 定义的名称
/// </summary>
public string Name { get; }
public IdentifierNode(string name) => Name = name;
}

View File

@@ -11,8 +11,19 @@ namespace Serein.Script.Node
/// </summary>
public class IfNode : ASTNode
{
/// <summary>
/// 条件来源
/// </summary>
public ASTNode Condition { get; }
/// <summary>
/// 条件为 true 时所执行的语句
/// </summary>
public List<ASTNode> TrueBranch { get; }
/// <summary>
/// 条件为 false 时所执行的语句
/// </summary>
public List<ASTNode> FalseBranch { get; }
public IfNode(ASTNode condition, List<ASTNode> trueBranch, List<ASTNode> falseBranch)
=> (Condition, TrueBranch, FalseBranch) = (condition, trueBranch, falseBranch);

View File

@@ -12,12 +12,12 @@ namespace Serein.Script.Node
public class MemberAccessNode : ASTNode
{
/// <summary>
/// 对象token
/// 对象来源
/// </summary>
public ASTNode Object { get; }
/// <summary>
/// 成员名称
/// 对象中要获取的成员名称
/// </summary>
public string MemberName { get; }

View File

@@ -12,11 +12,12 @@ namespace Serein.Script.Node
public class MemberAssignmentNode : ASTNode
{
/// <summary>
/// 作用的对象
/// 对象来源
/// </summary>
public ASTNode Object { get; }
/// <summary>
/// 赋值的成员(属性/字段)名称
/// 对象中要赋值的成员名称
/// </summary>
public string MemberName { get; }
/// <summary>

View File

@@ -12,17 +12,17 @@ namespace Serein.Script.Node
public class MemberFunctionCallNode : ASTNode
{
/// <summary>
/// 需要被调用的对象
/// 对象来源
/// </summary>
public ASTNode Object { get; }
/// <summary>
/// 调用的方法名称
/// 对象中要调用的方法名称
/// </summary>
public string FunctionName { get; }
/// <summary>
/// 方法参数
/// 方法参数来源
/// </summary>
public List<ASTNode> Arguments { get; }

View File

@@ -11,7 +11,14 @@ namespace Serein.Script.Node
/// </summary>
public class ObjectInstantiationNode : ASTNode
{
/// <summary>
/// 类型名称
/// </summary>
public string TypeName { get; }
/// <summary>
/// 构造方法的参数来源
/// </summary>
public List<ASTNode> Arguments { get; }
public ObjectInstantiationNode(string typeName, List<ASTNode> arguments)
{

View File

@@ -0,0 +1,15 @@
namespace Serein.Script.Node
{
public class ObjectMemberExpressionNode : ASTNode
{
/// <summary>
/// 对象成员(嵌套获取)
/// </summary>
public ASTNode Value { get; }
public ObjectMemberExpressionNode(ASTNode value)
{
this.Value = value;
}
}
}

View File

@@ -11,6 +11,9 @@ namespace Serein.Script.Node
/// </summary>
public class ProgramNode : ASTNode
{
/// <summary>
/// 程序可执行的语句
/// </summary>
public List<ASTNode> Statements { get; }
public ProgramNode(List<ASTNode> statements)

View File

@@ -11,6 +11,9 @@ namespace Serein.Script.Node
/// </summary>
public class ReturnNode : ASTNode
{
/// <summary>
/// 返回值来源
/// </summary>
public ASTNode Value { get; }
public ReturnNode(ASTNode returnNode)

View File

@@ -11,7 +11,14 @@ namespace Serein.Script.Node
/// </summary>
public class WhileNode : ASTNode
{
/// <summary>
/// 循环条件值来源
/// </summary>
public ASTNode Condition { get; }
/// <summary>
/// 循环中语句块
/// </summary>
public List<ASTNode> Body { get; }
public WhileNode(ASTNode condition, List<ASTNode> body) => (Condition, Body) = (condition, body);
}

View File

@@ -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)
{
}*/
}
}

View File

@@ -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; }
/// <summary>
/// 定义的变量
/// </summary>
private Dictionary<string, object> _variables = new Dictionary<string, object>();
/// <summary>
/// 取消令牌源,用于控制脚本的执行
/// </summary>
private CancellationTokenSource _tokenSource = new CancellationTokenSource();
/// <summary>
/// 是否该退出了
/// </summary>
public bool IsReturn => _tokenSource.IsCancellationRequested;
/// <summary>
/// 是否严格检查 Null 值 (禁止使用 Null
/// </summary>
public bool IsCheckNullValue { get; set; }
/// <summary>
/// 是否需要提前返回(用于脚本中提前结束)
/// </summary>
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();
}
}
}

View File

@@ -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()}";
}
}
}

View File

@@ -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()}";
}
}
/// <summary>
/// 脚本运行上下文
/// </summary>
public interface IScriptInvokeContext
{
/// <summary>
/// 脚本运行的流程上下文,包含了流程上下文和变量等信息
/// </summary>
IDynamicContext FlowContext { get; }
/// <summary>
/// 是否该退出了
/// </summary>
bool IsReturn { get; }
/// <summary>
/// 是否严格检查 Null 值 (禁止使用 Null
/// </summary>
bool IsCheckNullValue { get; set; }
/// <summary>
/// 获取变量的值
/// </summary>
/// <param name="varName"></param>
/// <returns></returns>
object GetVarValue(string varName);
/// <summary>
/// 设置变量的值
/// </summary>
/// <param name="varName"></param>
/// <param name="value"></param>
/// <returns></returns>
bool SetVarValue(string varName, object value);
/// <summary>
/// 结束调用
/// </summary>
/// <returns></returns>
void OnExit();
}
public class ScriptInvokeContext : IScriptInvokeContext
{
public ScriptInvokeContext(IDynamicContext dynamicContext)
{
FlowContext = dynamicContext;
}
public IDynamicContext FlowContext{ get; }
/// <summary>
/// 定义的变量
/// </summary>
private Dictionary<string, object> _variables = new Dictionary<string, object>();
/// <summary>
/// 取消令牌源,用于控制脚本的执行
/// </summary>
private CancellationTokenSource _tokenSource = new CancellationTokenSource();
/// <summary>
/// 是否该退出了
/// </summary>
public bool IsReturn => _tokenSource.IsCancellationRequested;
/// <summary>
/// 是否严格检查 Null 值 (禁止使用 Null
/// </summary>
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();
}
}
/// <summary>
/// 脚本解释器,负责解析和执行 Serein 脚本
@@ -147,6 +21,9 @@ namespace Serein.Script
/// 挂载的函数
/// </summary>
private static Dictionary<string, DelegateDetails> _functionTable = new Dictionary<string, DelegateDetails>();
private static Dictionary<string, MethodInfo> _functionInfoTable = new Dictionary<string, MethodInfo>();
public static Dictionary<string, MethodInfo> FunctionInfoTable { get { return _functionInfoTable; } }
/// <summary>
/// 挂载的函数调用的对象(用于函数需要实例才能调用的场景)
@@ -158,6 +35,12 @@ namespace Serein.Script
/// </summary>
private Dictionary<string, Type> _classDefinition = new Dictionary<string, Type>();
/// <summary>
/// 类型分析器
/// </summary>
private SereinScriptTypeAnalysis typeAnalysis;
/// <summary>
/// 挂载静态函数
/// </summary>
@@ -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
}
}
/// <summary>
/// 设置类型分析器
/// </summary>
/// <param name="typeAnalysis"></param>
public void SetTypeAnalysis(SereinScriptTypeAnalysis typeAnalysis)
{
this.typeAnalysis = typeAnalysis;
}
/// <summary>
/// 入口节点
/// </summary>
/// <param name="programNode"></param>
/// <returns></returns>
private async Task<object?> ExecutionProgramNodeAsync(IScriptInvokeContext context, ProgramNode programNode)
private async Task<object?> 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
/// <param name="ifNode"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
private async Task ExecutionIfNodeAsync(IScriptInvokeContext context, IfNode ifNode)
private async Task<object?> 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;
}
}
/// <summary>
@@ -312,14 +217,14 @@ namespace Serein.Script
/// <param name="whileNode"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
private async Task ExectutionWhileNodeAsync(IScriptInvokeContext context, WhileNode whileNode)
private async Task<object?> 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;
}
/// <summary>
@@ -344,13 +260,28 @@ namespace Serein.Script
/// <returns></returns>
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<object> 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
/// <param name="memberAccessNode"></param>
/// <returns></returns>
/// <exception cref="SereinSciptException"></exception>
public async Task<object?> GetValue(IScriptInvokeContext context, MemberAccessNode memberAccessNode)
public async Task<object?> GetMemberValue(IScriptInvokeContext context, MemberAccessNode memberAccessNode)
{
var target = await EvaluateAsync(context, memberAccessNode.Object);
var lastMember = memberAccessNode.MemberName;
@@ -654,7 +603,7 @@ namespace Serein.Script
/// <exception cref="SereinSciptException"></exception>
public async Task<object?> 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
/// <summary>
/// 缓存method委托
/// </summary>
private Dictionary<string, DelegateDetails> MethodToDelegateCaches { get; } = new Dictionary<string, DelegateDetails>();
private Dictionary<long, DelegateDetails> MethodToDelegateCaches { get; } = new Dictionary<long, DelegateDetails>();
public async Task<object?> 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);
}

View File

@@ -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;
/// <summary>
/// 关键字,防止声明为变量
/// </summary>
@@ -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
}
/// <summary>
/// 根据 token 重置Lexer
/// </summary>
/// <param name="token"></param>
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 == '\'')
{

View File

@@ -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抽象语法树根节点。
/// </summary>
/// <returns></returns>
public ASTNode Parse()
public ProgramNode Parse()
{
return Program();
}
@@ -43,7 +46,7 @@ namespace Serein.Script
/// 解析整个程序直到遇到文件结尾EOF为止。
/// </summary>
/// <returns></returns>
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
/// <returns></returns>
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<ASTNode> nodes = new List<ASTNode>(); // 表达对象成员路径的节点
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<ASTNode> rightValueNode = new List<ASTNode>(); // 表达对象成员路径的节点*/
}
}
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<ASTNode> nodes = new List<ASTNode>();
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<ASTNode>();
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);
}
/// <summary>
/// 指定对象解析集合索引行为(数组或字典)
/// </summary>
/// <returns></returns>
/// <exception cref="Exception"></exception>
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);
}
/// <summary>
@@ -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<ASTNode>();
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<ASTNode>();
bool isBreak = false;
while (_currentToken.Type != TokenType.ParenthesisRight)
var arguments = new List<ASTNode>();
// 获取参数
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<ASTNode> body = new List<ASTNode>();
@@ -645,43 +958,131 @@ namespace Serein.Script
return new WhileNode(condition, body).SetTokenInfo(_currentToken);
}
/* /// <summary>
/// 解析表达式。
/// </summary>
/// <returns></returns>
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;
}
/// <summary>
/// 解析项Term比较运算符
/// </summary>
/// <returns></returns>
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;
}*/
/// <summary>
/// 解析表达式
/// 顶层布尔表达式
/// </summary>
/// <returns></returns>
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;
}
/// <summary>
/// 比较表达式(==, !=, <, <=, >, >=
/// </summary>
/// <returns></returns>
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;
}
/// <summary>
/// 加减
/// </summary>
/// <returns></returns>
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;
}
/// <summary>
/// 解析项Term用于处理加减乘除等运算符。
/// 乘除
/// </summary>
/// <returns></returns>
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
/// <exception cref="Exception"></exception>
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<ASTNode> nodes = new List<ASTNode>();
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} " );
}
}

View File

@@ -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
{
/// <summary>
/// 脚本类型分析
/// </summary>
public class SereinScriptTypeAnalysis
{
private Dictionary<string, SymbolInfo> SymbolInfos = new Dictionary<string, SymbolInfo>();
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
{
}
}
/// <summary>
/// 符号表
/// </summary>
public Dictionary<ASTNode, Type> NodeSymbolInfos { get; } = new Dictionary<ASTNode, Type>();
/// <summary>
/// 类型分析、校验
/// </summary>
/// <param name="node"></param>
/// <exception cref="NotImplementedException"></exception>
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;
}
}
/// <summary>
/// 类型获取
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
/// <exception cref="NotImplementedException"></exception>
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;
}
}
/// <summary>
/// 获取某个集合类型支持的索引参数类型
/// </summary>
/// <param name="collectionType">集合类型</param>
/// <param name="indexType">索引</param>
/// <param name="resultType">获取到的类型</param>
/// <returns></returns>
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<K, V>
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<T>
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<PropertyInfo>()
.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
/// <summary>
/// 符号表
/// </summary>
public Dictionary<string, SymbolInfo> SymbolInfos { get; } = new Dictionary<string, SymbolInfo>();
/* 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;
}
/// <summary>
/// 追踪类型
@@ -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}");
}
}*/

View File

@@ -17,7 +17,7 @@ namespace Serein.Script.Symbol
/// <summary>
/// 符号信息
/// </summary>
internal class SymbolInfo
public class SymbolInfo
{
/// <summary>
/// 符号名称