mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-03 00:00:49 +08:00
为Serein.Script增加类型分析,增加了更加详细的Number类型节点,优化了对象节点的链式表达式,修复了Lexer分析词法时,部分Token代码属性错误的问题。
This commit is contained in:
@@ -14,7 +14,17 @@ namespace Serein.Library.Utils
|
|||||||
public class DynamicObjectHelper
|
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>
|
/// <summary>
|
||||||
/// 获取运行时创建过的类型
|
/// 获取运行时创建过的类型
|
||||||
@@ -82,6 +92,8 @@ namespace Serein.Library.Utils
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建具有属性的类型
|
/// 创建具有属性的类型
|
||||||
/// </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 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)
|
foreach (var kvp in properties)
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ namespace Serein.NodeFlow.Model
|
|||||||
public override bool IsBase => true;
|
public override bool IsBase => true;
|
||||||
|
|
||||||
private IScriptFlowApi ScriptFlowApi;
|
private IScriptFlowApi ScriptFlowApi;
|
||||||
private ASTNode mainNode;
|
private ProgramNode programNode;
|
||||||
private SereinScriptInterpreter ScriptInterpreter;
|
private SereinScriptInterpreter ScriptInterpreter;
|
||||||
private bool IsScriptChanged = false;
|
private bool IsScriptChanged = false;
|
||||||
|
|
||||||
@@ -167,8 +167,10 @@ namespace Serein.NodeFlow.Model
|
|||||||
var script = sb.ToString();
|
var script = sb.ToString();
|
||||||
var p = new SereinScriptParser(script);
|
var p = new SereinScriptParser(script);
|
||||||
//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)
|
catch (Exception ex)
|
||||||
@@ -185,7 +187,8 @@ namespace Serein.NodeFlow.Model
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public override async Task<FlowResult> ExecutingAsync(IDynamicContext context, CancellationToken token)
|
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>
|
/// <summary>
|
||||||
@@ -237,7 +240,8 @@ namespace Serein.NodeFlow.Model
|
|||||||
|
|
||||||
if (token.IsCancellationRequested) return null;
|
if (token.IsCancellationRequested) return null;
|
||||||
|
|
||||||
var result = await ScriptInterpreter.InterpretAsync(scriptContext, mainNode); // 从入口节点执行
|
|
||||||
|
var result = await ScriptInterpreter.InterpretAsync(scriptContext, programNode); // 从入口节点执行
|
||||||
envEvent.FlowRunComplete -= onFlowStop;
|
envEvent.FlowRunComplete -= onFlowStop;
|
||||||
return new FlowResult(this.Guid, context, result);
|
return new FlowResult(this.Guid, context, result);
|
||||||
}
|
}
|
||||||
@@ -253,6 +257,10 @@ namespace Serein.NodeFlow.Model
|
|||||||
{
|
{
|
||||||
public static DateTime GetNow() => DateTime.Now;
|
public static DateTime GetNow() => DateTime.Now;
|
||||||
|
|
||||||
|
public static int Add(int Left, int Right)
|
||||||
|
{
|
||||||
|
return Left + Right;
|
||||||
|
}
|
||||||
|
|
||||||
#region 常用的类型转换
|
#region 常用的类型转换
|
||||||
public static bool BoolOf(object value)
|
public static bool BoolOf(object value)
|
||||||
|
|||||||
@@ -87,9 +87,11 @@ namespace Serein.Script
|
|||||||
|
|
||||||
public static Type EvaluateType(Type leftType, string op, Type rightType)
|
public static Type EvaluateType(Type leftType, string op, Type rightType)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (leftType == null || rightType == null)
|
if (leftType == null || rightType == null)
|
||||||
throw new ArgumentNullException("操作数类型不能为 null");
|
throw new ArgumentNullException("操作数类型不能为 null");
|
||||||
|
|
||||||
|
|
||||||
// 字符串拼接
|
// 字符串拼接
|
||||||
if (op == "+" && (leftType == typeof(string) || rightType == typeof(string)))
|
if (op == "+" && (leftType == typeof(string) || rightType == typeof(string)))
|
||||||
return typeof(string);
|
return typeof(string);
|
||||||
|
|||||||
51
Serein.Script/IScriptInvokeContext.cs
Normal file
51
Serein.Script/IScriptInvokeContext.cs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,13 +15,14 @@ namespace Serein.Script.Node
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 变量名称
|
/// 变量名称
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Variable { get; }
|
//public string Variable { get; }
|
||||||
|
public ASTNode Target { get; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 对应的节点
|
/// 对应的节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ASTNode Value { 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,19 @@ namespace Serein.Script.Node
|
|||||||
|
|
||||||
public class BinaryOperationNode : ASTNode
|
public class BinaryOperationNode : ASTNode
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 左元
|
||||||
|
/// </summary>
|
||||||
public ASTNode Left { get; }
|
public ASTNode Left { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 操作符(布尔运算符 > 比较运算符 > 加减乘除 )
|
||||||
|
/// </summary>
|
||||||
public string Operator { get; }
|
public string Operator { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 右元
|
||||||
|
/// </summary>
|
||||||
public ASTNode Right { get; }
|
public ASTNode Right { get; }
|
||||||
|
|
||||||
public BinaryOperationNode(ASTNode left, string op, ASTNode right)
|
public BinaryOperationNode(ASTNode left, string op, ASTNode right)
|
||||||
|
|||||||
@@ -11,8 +11,17 @@ namespace Serein.Script.Node
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class ClassTypeDefinitionNode : ASTNode
|
public class ClassTypeDefinitionNode : ASTNode
|
||||||
{
|
{
|
||||||
|
[Obsolete("此属性已经过时,可能在下一个版本中移除", false)]
|
||||||
public bool IsOverlay { get; set; }
|
public bool IsOverlay { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 类名称
|
||||||
|
/// </summary>
|
||||||
public string ClassName { get; }
|
public string ClassName { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 字段名称及字段类型
|
||||||
|
/// </summary>
|
||||||
public Dictionary<string, Type> Fields { get; }
|
public Dictionary<string, Type> Fields { get; }
|
||||||
|
|
||||||
public ClassTypeDefinitionNode(Dictionary<string, Type> fields, string className, bool isOverlay)
|
public ClassTypeDefinitionNode(Dictionary<string, Type> fields, string className, bool isOverlay)
|
||||||
|
|||||||
@@ -11,12 +11,19 @@ namespace Serein.Script.Node
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class CollectionIndexNode : ASTNode
|
public class CollectionIndexNode : ASTNode
|
||||||
{
|
{
|
||||||
public ASTNode TargetValue { get; }
|
/// <summary>
|
||||||
public ASTNode IndexValue { get; }
|
/// 集合来源
|
||||||
public CollectionIndexNode(ASTNode collectionValue,ASTNode indexValue)
|
/// </summary>
|
||||||
|
public ASTNode Collection { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 索引来源
|
||||||
|
/// </summary>
|
||||||
|
public ASTNode Index { get; }
|
||||||
|
public CollectionIndexNode(ASTNode TargetValue,ASTNode indexValue)
|
||||||
{
|
{
|
||||||
this.TargetValue = collectionValue;
|
this.Collection = TargetValue;
|
||||||
this.IndexValue = indexValue;
|
this.Index = indexValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,14 @@ namespace Serein.Script.Node
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class FunctionCallNode : ASTNode
|
public class FunctionCallNode : ASTNode
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 方法名称
|
||||||
|
/// </summary>
|
||||||
public string FunctionName { get; }
|
public string FunctionName { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 参数来源
|
||||||
|
/// </summary>
|
||||||
public List<ASTNode> Arguments { get; }
|
public List<ASTNode> Arguments { get; }
|
||||||
|
|
||||||
public FunctionCallNode(string functionName, List<ASTNode> arguments)
|
public FunctionCallNode(string functionName, List<ASTNode> arguments)
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ namespace Serein.Script.Node
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class IdentifierNode : ASTNode
|
public class IdentifierNode : ASTNode
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 定义的名称
|
||||||
|
/// </summary>
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
public IdentifierNode(string name) => Name = name;
|
public IdentifierNode(string name) => Name = name;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,19 @@ namespace Serein.Script.Node
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class IfNode : ASTNode
|
public class IfNode : ASTNode
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 条件来源
|
||||||
|
/// </summary>
|
||||||
public ASTNode Condition { get; }
|
public ASTNode Condition { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 条件为 true 时所执行的语句
|
||||||
|
/// </summary>
|
||||||
public List<ASTNode> TrueBranch { get; }
|
public List<ASTNode> TrueBranch { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 条件为 false 时所执行的语句
|
||||||
|
/// </summary>
|
||||||
public List<ASTNode> FalseBranch { get; }
|
public List<ASTNode> FalseBranch { get; }
|
||||||
public IfNode(ASTNode condition, List<ASTNode> trueBranch, List<ASTNode> falseBranch)
|
public IfNode(ASTNode condition, List<ASTNode> trueBranch, List<ASTNode> falseBranch)
|
||||||
=> (Condition, TrueBranch, FalseBranch) = (condition, trueBranch, falseBranch);
|
=> (Condition, TrueBranch, FalseBranch) = (condition, trueBranch, falseBranch);
|
||||||
|
|||||||
@@ -12,12 +12,12 @@ namespace Serein.Script.Node
|
|||||||
public class MemberAccessNode : ASTNode
|
public class MemberAccessNode : ASTNode
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 对象token
|
/// 对象来源
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ASTNode Object { get; }
|
public ASTNode Object { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 成员名称
|
/// 对象中要获取的成员的名称
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string MemberName { get; }
|
public string MemberName { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -12,11 +12,12 @@ namespace Serein.Script.Node
|
|||||||
public class MemberAssignmentNode : ASTNode
|
public class MemberAssignmentNode : ASTNode
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 作用的对象
|
/// 对象来源
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ASTNode Object { get; }
|
public ASTNode Object { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 被赋值的成员(属性/字段)名称
|
/// 对象中要赋值的成员的名称
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string MemberName { get; }
|
public string MemberName { get; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -12,17 +12,17 @@ namespace Serein.Script.Node
|
|||||||
public class MemberFunctionCallNode : ASTNode
|
public class MemberFunctionCallNode : ASTNode
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 需要被调用的对象
|
/// 对象来源
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ASTNode Object { get; }
|
public ASTNode Object { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 被调用的方法名称
|
/// 对象中要调用的方法的名称
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string FunctionName { get; }
|
public string FunctionName { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 方法参数
|
/// 方法参数来源
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<ASTNode> Arguments { get; }
|
public List<ASTNode> Arguments { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,14 @@ namespace Serein.Script.Node
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class ObjectInstantiationNode : ASTNode
|
public class ObjectInstantiationNode : ASTNode
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 类型名称
|
||||||
|
/// </summary>
|
||||||
public string TypeName { get; }
|
public string TypeName { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造方法的参数来源
|
||||||
|
/// </summary>
|
||||||
public List<ASTNode> Arguments { get; }
|
public List<ASTNode> Arguments { get; }
|
||||||
public ObjectInstantiationNode(string typeName, List<ASTNode> arguments)
|
public ObjectInstantiationNode(string typeName, List<ASTNode> arguments)
|
||||||
{
|
{
|
||||||
|
|||||||
15
Serein.Script/Node/ObjectMemberExpressionNode.cs
Normal file
15
Serein.Script/Node/ObjectMemberExpressionNode.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,9 @@ namespace Serein.Script.Node
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class ProgramNode : ASTNode
|
public class ProgramNode : ASTNode
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 程序可执行的语句
|
||||||
|
/// </summary>
|
||||||
public List<ASTNode> Statements { get; }
|
public List<ASTNode> Statements { get; }
|
||||||
|
|
||||||
public ProgramNode(List<ASTNode> statements)
|
public ProgramNode(List<ASTNode> statements)
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ namespace Serein.Script.Node
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class ReturnNode : ASTNode
|
public class ReturnNode : ASTNode
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 返回值来源
|
||||||
|
/// </summary>
|
||||||
public ASTNode Value { get; }
|
public ASTNode Value { get; }
|
||||||
|
|
||||||
public ReturnNode(ASTNode returnNode)
|
public ReturnNode(ASTNode returnNode)
|
||||||
|
|||||||
@@ -11,7 +11,14 @@ namespace Serein.Script.Node
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class WhileNode : ASTNode
|
public class WhileNode : ASTNode
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 循环条件值来源
|
||||||
|
/// </summary>
|
||||||
public ASTNode Condition { get; }
|
public ASTNode Condition { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 循环中语句块
|
||||||
|
/// </summary>
|
||||||
public List<ASTNode> Body { get; }
|
public List<ASTNode> Body { get; }
|
||||||
public WhileNode(ASTNode condition, List<ASTNode> body) => (Condition, Body) = (condition, body);
|
public WhileNode(ASTNode condition, List<ASTNode> body) => (Condition, Body) = (condition, body);
|
||||||
}
|
}
|
||||||
|
|||||||
19
Serein.Script/NodeInterpreterExtension.cs
Normal file
19
Serein.Script/NodeInterpreterExtension.cs
Normal 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)
|
||||||
|
{
|
||||||
|
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
79
Serein.Script/ScriptInvokeContext.cs
Normal file
79
Serein.Script/ScriptInvokeContext.cs
Normal 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
16
Serein.Script/SereinSciptException.cs
Normal file
16
Serein.Script/SereinSciptException.cs
Normal 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()}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using Serein.Library;
|
using Serein.Library;
|
||||||
using Serein.Library.Api;
|
|
||||||
using Serein.Library.Utils;
|
using Serein.Library.Utils;
|
||||||
using Serein.Script.Node;
|
using Serein.Script.Node;
|
||||||
using System.ComponentModel.Design;
|
using System.ComponentModel.Design;
|
||||||
@@ -11,131 +10,6 @@ using System.Xml.Linq;
|
|||||||
|
|
||||||
namespace Serein.Script
|
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>
|
/// <summary>
|
||||||
/// 脚本解释器,负责解析和执行 Serein 脚本
|
/// 脚本解释器,负责解析和执行 Serein 脚本
|
||||||
@@ -147,6 +21,9 @@ namespace Serein.Script
|
|||||||
/// 挂载的函数
|
/// 挂载的函数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static Dictionary<string, DelegateDetails> _functionTable = new Dictionary<string, DelegateDetails>();
|
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>
|
/// <summary>
|
||||||
/// 挂载的函数调用的对象(用于函数需要实例才能调用的场景)
|
/// 挂载的函数调用的对象(用于函数需要实例才能调用的场景)
|
||||||
@@ -158,6 +35,12 @@ namespace Serein.Script
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private Dictionary<string, Type> _classDefinition = new Dictionary<string, Type>();
|
private Dictionary<string, Type> _classDefinition = new Dictionary<string, Type>();
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 类型分析器
|
||||||
|
/// </summary>
|
||||||
|
private SereinScriptTypeAnalysis typeAnalysis;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 挂载静态函数
|
/// 挂载静态函数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -166,6 +49,7 @@ namespace Serein.Script
|
|||||||
public static void AddStaticFunction(string functionName, MethodInfo methodInfo)
|
public static void AddStaticFunction(string functionName, MethodInfo methodInfo)
|
||||||
{
|
{
|
||||||
_functionTable[functionName] = new DelegateDetails(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>
|
||||||
/// 入口节点
|
/// 入口节点
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="programNode"></param>
|
/// <param name="programNode"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private async Task<object?> ExecutionProgramNodeAsync(IScriptInvokeContext context, ProgramNode programNode)
|
private async Task<object?> ExecutionProgramNodeAsync(IScriptInvokeContext context,ProgramNode programNode)
|
||||||
{
|
{
|
||||||
// 加载变量
|
// 加载变量
|
||||||
ASTNode statement = null;
|
ASTNode statement = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
// 遍历 ProgramNode 中的所有语句并执行它们
|
// 遍历 ProgramNode 中的所有语句并执行它们
|
||||||
for (int index = 0; index < programNode.Statements.Count; index++)
|
for (int index = 0; index < programNode.Statements.Count; index++)
|
||||||
{
|
{
|
||||||
@@ -240,7 +131,11 @@ namespace Serein.Script
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await InterpretAsync(context, statement);
|
var result = await InterpretAsync(context, statement);
|
||||||
|
if (context.IsNeedReturn)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -268,10 +163,10 @@ namespace Serein.Script
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var isOverlay = true; // classTypeDefinitionNode.IsOverlay;
|
//var isOverlay = true; // classTypeDefinitionNode.IsOverlay;
|
||||||
|
|
||||||
var type = DynamicObjectHelper.CreateTypeWithProperties(classTypeDefinitionNode.Fields, classTypeDefinitionNode.ClassName, isOverlay); // 覆盖
|
var type = DynamicObjectHelper.CreateTypeWithProperties(classTypeDefinitionNode.Fields, classTypeDefinitionNode.ClassName); // 覆盖
|
||||||
classTypeDefinitionNode.IsOverlay = false; // 已经加载过,则不再覆盖
|
//classTypeDefinitionNode.IsOverlay = false; // 已经加载过,则不再覆盖
|
||||||
_classDefinition[classTypeDefinitionNode.ClassName] = type; // 定义对象
|
_classDefinition[classTypeDefinitionNode.ClassName] = type; // 定义对象
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,7 +176,7 @@ namespace Serein.Script
|
|||||||
/// <param name="ifNode"></param>
|
/// <param name="ifNode"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <exception cref="Exception"></exception>
|
/// <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");
|
var result = await EvaluateAsync(context, ifNode.Condition) ?? throw new SereinSciptException(ifNode, $"条件语句返回了 null");
|
||||||
|
|
||||||
@@ -290,20 +185,30 @@ namespace Serein.Script
|
|||||||
throw new SereinSciptException(ifNode, "条件语句返回值不为 bool 类型");
|
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)
|
return null;
|
||||||
{
|
|
||||||
await InterpretAsync(context, trueNode);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
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>
|
/// <summary>
|
||||||
@@ -312,14 +217,14 @@ namespace Serein.Script
|
|||||||
/// <param name="whileNode"></param>
|
/// <param name="whileNode"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <exception cref="Exception"></exception>
|
/// <exception cref="Exception"></exception>
|
||||||
private async Task ExectutionWhileNodeAsync(IScriptInvokeContext context, WhileNode whileNode)
|
private async Task<object?> ExectutionWhileNodeAsync(IScriptInvokeContext context, WhileNode whileNode)
|
||||||
{
|
{
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (context.IsReturn) // 停止流程
|
if (context.IsReturn) // 停止流程
|
||||||
{
|
{
|
||||||
return;
|
throw new SereinSciptException(whileNode, $"while循环已由外部主动停止");
|
||||||
}
|
}
|
||||||
var result = await EvaluateAsync(context, whileNode.Condition) ?? throw new SereinSciptException(whileNode, $"条件语句返回了 null");
|
var result = await EvaluateAsync(context, whileNode.Condition) ?? throw new SereinSciptException(whileNode, $"条件语句返回了 null");
|
||||||
if (result is not bool condition)
|
if (result is not bool condition)
|
||||||
@@ -330,11 +235,22 @@ namespace Serein.Script
|
|||||||
{
|
{
|
||||||
break;
|
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>
|
/// <summary>
|
||||||
@@ -344,13 +260,28 @@ namespace Serein.Script
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private async Task ExecutionAssignmentNodeAsync(IScriptInvokeContext context, AssignmentNode assignmentNode)
|
private async Task ExecutionAssignmentNodeAsync(IScriptInvokeContext context, AssignmentNode assignmentNode)
|
||||||
{
|
{
|
||||||
var tmp = await EvaluateAsync(context, assignmentNode.Value);
|
if(assignmentNode.Target is IdentifierNode identifierNode)
|
||||||
if(tmp is not null)
|
{
|
||||||
|
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)
|
private async Task<object> InterpretFunctionCallAsync(IScriptInvokeContext context, FunctionCallNode functionCallNode)
|
||||||
{
|
{
|
||||||
if (functionCallNode.FunctionName.Equals("GetFlowContext", StringComparison.OrdinalIgnoreCase))
|
if (functionCallNode.FunctionName.Equals("GetFlowContext", StringComparison.OrdinalIgnoreCase))
|
||||||
@@ -427,16 +358,18 @@ namespace Serein.Script
|
|||||||
case AssignmentNode assignment: // 出现在 = 右侧的表达式
|
case AssignmentNode assignment: // 出现在 = 右侧的表达式
|
||||||
await ExecutionAssignmentNodeAsync(context, assignment);
|
await ExecutionAssignmentNodeAsync(context, assignment);
|
||||||
break;
|
break;
|
||||||
|
case ObjectMemberExpressionNode objectMemberExpressionNode:
|
||||||
|
break;
|
||||||
case MemberAssignmentNode memberAssignmentNode: // 设置对象属性
|
case MemberAssignmentNode memberAssignmentNode: // 设置对象属性
|
||||||
await SetMemberValue(context, memberAssignmentNode);
|
await SetMemberValue(context, memberAssignmentNode);
|
||||||
break;
|
break;
|
||||||
case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用
|
case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用
|
||||||
return await CallMemberFunction(context, memberFunctionCallNode);
|
return await CallMemberFunction(context, memberFunctionCallNode);
|
||||||
case IfNode ifNode: // 执行 if...else... 语句块
|
case IfNode ifNode: // 执行 if...else... 语句块
|
||||||
await ExecutionIfNodeAsync(context, ifNode);
|
return await ExecutionIfNodeAsync(context, ifNode);
|
||||||
break;
|
break;
|
||||||
case WhileNode whileNode: // 循环语句块
|
case WhileNode whileNode: // 循环语句块
|
||||||
await ExectutionWhileNodeAsync(context, whileNode);
|
return await ExectutionWhileNodeAsync(context, whileNode);
|
||||||
break;
|
break;
|
||||||
case FunctionCallNode functionCallNode: // 方法调用节点
|
case FunctionCallNode functionCallNode: // 方法调用节点
|
||||||
return await InterpretFunctionCallAsync(context, functionCallNode);
|
return await InterpretFunctionCallAsync(context, functionCallNode);
|
||||||
@@ -517,13 +450,13 @@ namespace Serein.Script
|
|||||||
case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用
|
case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用
|
||||||
return await CallMemberFunction(context, memberFunctionCallNode);
|
return await CallMemberFunction(context, memberFunctionCallNode);
|
||||||
case MemberAccessNode memberAccessNode: // 对象成员访问
|
case MemberAccessNode memberAccessNode: // 对象成员访问
|
||||||
return await GetValue(context, memberAccessNode);
|
return await GetMemberValue(context, memberAccessNode);
|
||||||
case CollectionIndexNode collectionIndexNode:
|
case CollectionIndexNode collectionIndexNode:
|
||||||
return await GetCollectionValue(context, collectionIndexNode);
|
return await GetCollectionValue(context, collectionIndexNode);
|
||||||
case ReturnNode returnNode: // 返回内容
|
case ReturnNode returnNode: // 返回内容
|
||||||
return await EvaluateAsync(context, returnNode.Value); // 直接返回响应的内容
|
return await EvaluateAsync(context, returnNode.Value); // 直接返回响应的内容
|
||||||
//case ObjectInstantiationNode objectInstantiationNode: // 返回内容
|
case ObjectMemberExpressionNode objectMemberExpressionNode: // 对象链式表达式
|
||||||
|
return await EvaluateAsync(context, objectMemberExpressionNode.Value);
|
||||||
default:
|
default:
|
||||||
throw new SereinSciptException(node, $"解释器 EvaluateAsync() 未实现{node}节点行为");
|
throw new SereinSciptException(node, $"解释器 EvaluateAsync() 未实现{node}节点行为");
|
||||||
}
|
}
|
||||||
@@ -611,8 +544,24 @@ namespace Serein.Script
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var convertedValue = Convert.ChangeType(value, lastProperty.PropertyType);
|
if(value is null)
|
||||||
lastProperty.SetValue(target, convertedValue);
|
{
|
||||||
|
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>
|
/// <param name="memberAccessNode"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <exception cref="SereinSciptException"></exception>
|
/// <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 target = await EvaluateAsync(context, memberAccessNode.Object);
|
||||||
var lastMember = memberAccessNode.MemberName;
|
var lastMember = memberAccessNode.MemberName;
|
||||||
@@ -654,7 +603,7 @@ namespace Serein.Script
|
|||||||
/// <exception cref="SereinSciptException"></exception>
|
/// <exception cref="SereinSciptException"></exception>
|
||||||
public async Task<object?> GetCollectionValue(IScriptInvokeContext context, CollectionIndexNode collectionIndexNode)
|
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)
|
if (target is null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException($"解析{collectionIndexNode}节点时,TargetValue返回空。");
|
throw new ArgumentNullException($"解析{collectionIndexNode}节点时,TargetValue返回空。");
|
||||||
@@ -669,7 +618,7 @@ namespace Serein.Script
|
|||||||
var method = targetType.GetMethod("get_Item", BindingFlags.Public | BindingFlags.Instance);
|
var method = targetType.GetMethod("get_Item", BindingFlags.Public | BindingFlags.Instance);
|
||||||
if (method is not null)
|
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 });
|
var result = method.Invoke(target, new object[] { key });
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -678,7 +627,7 @@ namespace Serein.Script
|
|||||||
#region 处理集合对象
|
#region 处理集合对象
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var indexValue = await EvaluateAsync(context, collectionIndexNode.IndexValue); // 获取索引值
|
var indexValue = await EvaluateAsync(context, collectionIndexNode.Index); // 获取索引值
|
||||||
object? result;
|
object? result;
|
||||||
if (indexValue is int index)
|
if (indexValue is int index)
|
||||||
{
|
{
|
||||||
@@ -702,6 +651,10 @@ namespace Serein.Script
|
|||||||
result = list[index];
|
result = list[index];
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
else if (target is string chars)
|
||||||
|
{
|
||||||
|
return chars[index];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new ArgumentException($"解析{collectionIndexNode}节点时,左值并非有效集合。");
|
throw new ArgumentException($"解析{collectionIndexNode}节点时,左值并非有效集合。");
|
||||||
@@ -717,30 +670,58 @@ namespace Serein.Script
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 缓存method委托
|
/// 缓存method委托
|
||||||
/// </summary>
|
/// </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)
|
public async Task<object?> CallMemberFunction(IScriptInvokeContext context, MemberFunctionCallNode memberFunctionCallNode)
|
||||||
{
|
{
|
||||||
var target = await EvaluateAsync(context, memberFunctionCallNode.Object);
|
var target = await EvaluateAsync(context, memberFunctionCallNode.Object);
|
||||||
var lastMember = memberFunctionCallNode.FunctionName;
|
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);
|
delegateDetails = new DelegateDetails(methodInfo);
|
||||||
MethodToDelegateCaches[methodInfo.Name] = delegateDetails;
|
MethodToDelegateCaches[methodInfo.MetadataToken] = delegateDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(memberFunctionCallNode.Arguments.Count == 0)
|
||||||
|
|
||||||
var arguments = new object?[memberFunctionCallNode.Arguments.Count];
|
|
||||||
for (int i = 0; i < memberFunctionCallNode.Arguments.Count; i++)
|
|
||||||
{
|
{
|
||||||
ASTNode? arg = memberFunctionCallNode.Arguments[i];
|
var reuslt = await delegateDetails.InvokeAsync(target, []);
|
||||||
arguments[i] = await EvaluateAsync(context, arg); // 评估每个参数
|
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using static System.Net.Mime.MediaTypeNames;
|
using static System.Net.Mime.MediaTypeNames;
|
||||||
@@ -137,8 +138,6 @@ namespace Serein.Script
|
|||||||
private int _index;
|
private int _index;
|
||||||
private int _row ;
|
private int _row ;
|
||||||
|
|
||||||
private int coreRangeStartIndex = 0;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 关键字,防止声明为变量
|
/// 关键字,防止声明为变量
|
||||||
/// </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; // 保存当前索引
|
int currentIndex = _index; // 保存当前索引
|
||||||
var currentRow = _row; // 保存当前行数
|
var currentRow = _row; // 保存当前行数
|
||||||
Token nextToken = NextToken(); // 获取下一个 token
|
Token nextToken = new Token(); ;
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
nextToken = NextToken(); // 获取下一个 token
|
||||||
|
}
|
||||||
_index = currentIndex; // 恢复索引到当前位置
|
_index = currentIndex; // 恢复索引到当前位置
|
||||||
_row = currentRow; // 恢复到当前行数
|
_row = currentRow; // 恢复到当前行数
|
||||||
return nextToken; // 返回下一个 token
|
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()
|
internal Token NextToken()
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -194,6 +208,7 @@ namespace Serein.Script
|
|||||||
{
|
{
|
||||||
return ReadString();
|
return ReadString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (currentChar == '\'')
|
if (currentChar == '\'')
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ using Serein.Library;
|
|||||||
using Serein.Library.Utils;
|
using Serein.Library.Utils;
|
||||||
using Serein.Script.Node;
|
using Serein.Script.Node;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Serein.Script
|
namespace Serein.Script
|
||||||
{
|
{
|
||||||
@@ -30,8 +32,9 @@ namespace Serein.Script
|
|||||||
/// 解析脚本并返回 AST(抽象语法树)根节点。
|
/// 解析脚本并返回 AST(抽象语法树)根节点。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public ASTNode Parse()
|
public ProgramNode Parse()
|
||||||
{
|
{
|
||||||
|
|
||||||
return Program();
|
return Program();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +46,7 @@ namespace Serein.Script
|
|||||||
/// 解析整个程序,直到遇到文件结尾(EOF)为止。
|
/// 解析整个程序,直到遇到文件结尾(EOF)为止。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private ASTNode Program()
|
private ProgramNode Program()
|
||||||
{
|
{
|
||||||
Statements.Clear();
|
Statements.Clear();
|
||||||
while (_currentToken.Type != TokenType.EOF)
|
while (_currentToken.Type != TokenType.EOF)
|
||||||
@@ -59,7 +62,6 @@ namespace Serein.Script
|
|||||||
var programNode = new ProgramNode(Statements);
|
var programNode = new ProgramNode(Statements);
|
||||||
programNode.SetTokenInfo(_currentToken); // 程序节点,包含所有解析的语句列表
|
programNode.SetTokenInfo(_currentToken); // 程序节点,包含所有解析的语句列表
|
||||||
|
|
||||||
SereinScriptTypeAnalysis typeAnalysis = new SereinScriptTypeAnalysis(programNode);
|
|
||||||
return programNode;
|
return programNode;
|
||||||
|
|
||||||
/*if (astNode is ClassTypeDefinitionNode)
|
/*if (astNode is ClassTypeDefinitionNode)
|
||||||
@@ -135,6 +137,7 @@ namespace Serein.Script
|
|||||||
if (_currentToken.Type == TokenType.Null)
|
if (_currentToken.Type == TokenType.Null)
|
||||||
{
|
{
|
||||||
// 处理 null 语句
|
// 处理 null 语句
|
||||||
|
return BooleanExpression();
|
||||||
return Expression();
|
return Expression();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +160,254 @@ namespace Serein.Script
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private ASTNode ParseIdentifier()
|
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();
|
var _tempToken = _lexer.PeekToken();
|
||||||
if (_tempToken.Type == TokenType.ParenthesisLeft)
|
if (_tempToken.Type == TokenType.ParenthesisLeft)
|
||||||
@@ -168,6 +418,7 @@ namespace Serein.Script
|
|||||||
else if (_tempToken.Type == TokenType.Dot)
|
else if (_tempToken.Type == TokenType.Dot)
|
||||||
{
|
{
|
||||||
// 对象成员的获取
|
// 对象成员的获取
|
||||||
|
|
||||||
return ParseMemberAccessOrAssignment();
|
return ParseMemberAccessOrAssignment();
|
||||||
}
|
}
|
||||||
else if (_tempToken.Type == TokenType.SquareBracketsLeft)
|
else if (_tempToken.Type == TokenType.SquareBracketsLeft)
|
||||||
@@ -213,7 +464,8 @@ namespace Serein.Script
|
|||||||
{
|
{
|
||||||
//_currentToken = _lexer.NextToken(); // 消耗操作符
|
//_currentToken = _lexer.NextToken(); // 消耗操作符
|
||||||
//_currentToken = _lexer.NextToken(); // 消耗操作符
|
//_currentToken = _lexer.NextToken(); // 消耗操作符
|
||||||
valueNode = Expression();
|
valueNode = BooleanExpression();
|
||||||
|
//valueNode = Expression();
|
||||||
}
|
}
|
||||||
else if (_tempToken.Type == TokenType.ParenthesisLeft)
|
else if (_tempToken.Type == TokenType.ParenthesisLeft)
|
||||||
{
|
{
|
||||||
@@ -224,9 +476,11 @@ namespace Serein.Script
|
|||||||
else
|
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)
|
if (_peekToken.Type == TokenType.Dot)
|
||||||
{
|
{
|
||||||
@@ -253,7 +507,7 @@ namespace Serein.Script
|
|||||||
{
|
{
|
||||||
|
|
||||||
_currentToken = _lexer.NextToken(); // Consume "let"
|
_currentToken = _lexer.NextToken(); // Consume "let"
|
||||||
string variable = _currentToken.Value.ToString(); // 变量名称
|
string variableName = _currentToken.Value.ToString(); // 变量名称
|
||||||
_currentToken = _lexer.NextToken(); // Consume identifier
|
_currentToken = _lexer.NextToken(); // Consume identifier
|
||||||
ASTNode value;
|
ASTNode value;
|
||||||
AssignmentNode assignmentNode;
|
AssignmentNode assignmentNode;
|
||||||
@@ -261,7 +515,8 @@ namespace Serein.Script
|
|||||||
{
|
{
|
||||||
// 定义一个变量,初始值为 null
|
// 定义一个变量,初始值为 null
|
||||||
value = new NullNode();
|
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信息
|
assignmentNode.SetTokenInfo(_currentToken); // 设置token信息
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -272,8 +527,10 @@ namespace Serein.Script
|
|||||||
throw new Exception("Expected '=' after variable name");
|
throw new Exception("Expected '=' after variable name");
|
||||||
_currentToken = _lexer.NextToken(); // 消耗操作符(“=”)
|
_currentToken = _lexer.NextToken(); // 消耗操作符(“=”)
|
||||||
var nodeToken = _currentToken;
|
var nodeToken = _currentToken;
|
||||||
value = Expression(); // 解析获取赋值表达式
|
value = BooleanExpression(); // 解析获取赋值表达式
|
||||||
assignmentNode = new AssignmentNode(variable, value); // 生成node
|
//value = Expression(); // 解析获取赋值表达式
|
||||||
|
var variableNode = new IdentifierNode(variableName).SetTokenInfo(_currentToken);
|
||||||
|
assignmentNode = new AssignmentNode(variableNode, value); // 生成node
|
||||||
assignmentNode.SetTokenInfo(nodeToken); // 设置token信息
|
assignmentNode.SetTokenInfo(nodeToken); // 设置token信息
|
||||||
_currentToken = _lexer.NextToken(); // 消耗分号
|
_currentToken = _lexer.NextToken(); // 消耗分号
|
||||||
}
|
}
|
||||||
@@ -316,7 +573,10 @@ namespace Serein.Script
|
|||||||
while (_currentToken.Type != TokenType.BraceRight)
|
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(); // 消耗类型
|
_currentToken = _lexer.NextToken(); // 消耗类型
|
||||||
var fieldName = _currentToken.Value.ToString(); // 获取定义的类名
|
var fieldName = _currentToken.Value.ToString(); // 获取定义的类名
|
||||||
_currentToken = _lexer.NextToken(); // 消耗字段名称
|
_currentToken = _lexer.NextToken(); // 消耗字段名称
|
||||||
@@ -334,7 +594,9 @@ namespace Serein.Script
|
|||||||
|
|
||||||
}
|
}
|
||||||
_currentToken = _lexer.NextToken(); // 消耗类型定义 } 括号
|
_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);
|
var node = new ClassTypeDefinitionNode(classFields, className, isOverlay);
|
||||||
_currentToken.Code = typeDefinitionCode;
|
_currentToken.Code = typeDefinitionCode;
|
||||||
node.SetTokenInfo(_currentToken);
|
node.SetTokenInfo(_currentToken);
|
||||||
@@ -361,7 +623,8 @@ namespace Serein.Script
|
|||||||
var arguments = new List<ASTNode>();
|
var arguments = new List<ASTNode>();
|
||||||
while (_currentToken.Type != TokenType.ParenthesisRight)
|
while (_currentToken.Type != TokenType.ParenthesisRight)
|
||||||
{
|
{
|
||||||
arguments.Add(Expression()); // 获取参数表达式
|
//arguments.Add(Expression()); // 获取参数表达式
|
||||||
|
arguments.Add(BooleanExpression()); // 获取参数表达式
|
||||||
if (_currentToken.Type == TokenType.Comma)
|
if (_currentToken.Type == TokenType.Comma)
|
||||||
{
|
{
|
||||||
_currentToken = _lexer.NextToken(); // consume ","
|
_currentToken = _lexer.NextToken(); // consume ","
|
||||||
@@ -383,17 +646,40 @@ namespace Serein.Script
|
|||||||
|
|
||||||
string collectionName = _currentToken.Value.ToString();
|
string collectionName = _currentToken.Value.ToString();
|
||||||
//_lexer.NextToken(); // consume "["
|
//_lexer.NextToken(); // consume "["
|
||||||
_currentToken = _lexer.NextToken(); // consume identifier
|
_currentToken = _lexer.NextToken(); // 消耗数组名称 identifier
|
||||||
// ParenthesisLeft
|
// ParenthesisLeft
|
||||||
if (_currentToken.Type != TokenType.SquareBracketsLeft)
|
if (_currentToken.Type != TokenType.SquareBracketsLeft)
|
||||||
throw new Exception("Expected '[' after function name");
|
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 "]"
|
_currentToken = _lexer.NextToken(); // 消耗 "]"
|
||||||
return new CollectionIndexNode(identifierNode,indexValue).SetTokenInfo(_currentToken);
|
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>
|
/// <summary>
|
||||||
@@ -425,7 +711,10 @@ namespace Serein.Script
|
|||||||
// 成员赋值 obj.Member = xxx;
|
// 成员赋值 obj.Member = xxx;
|
||||||
_currentToken = _lexer.NextToken(); // 消耗 "="
|
_currentToken = _lexer.NextToken(); // 消耗 "="
|
||||||
_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);
|
return new MemberAssignmentNode(identifierNode, memberName, valueNode).SetTokenInfo(_peekToken);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -465,27 +754,28 @@ namespace Serein.Script
|
|||||||
private ASTNode ParseMemberFunctionCall(ASTNode targetNode)
|
private ASTNode ParseMemberFunctionCall(ASTNode targetNode)
|
||||||
{
|
{
|
||||||
string functionName = _currentToken.Value.ToString(); // 函数名称
|
string functionName = _currentToken.Value.ToString(); // 函数名称
|
||||||
_currentToken = _lexer.NextToken(); // consume identifier
|
_currentToken = _lexer.NextToken(); // 消耗函数名称
|
||||||
|
|
||||||
if (_currentToken.Type != TokenType.ParenthesisLeft)
|
if (_currentToken.Type != TokenType.ParenthesisLeft)
|
||||||
throw new Exception("Expected '(' after function name");
|
throw new Exception("Expected '(' after function name");
|
||||||
|
|
||||||
_currentToken = _lexer.NextToken(); // consume "("
|
_currentToken = _lexer.NextToken(); // 消耗 "("
|
||||||
|
|
||||||
var arguments = new List<ASTNode>();
|
var arguments = new List<ASTNode>();
|
||||||
while (_currentToken.Type != TokenType.ParenthesisRight)
|
while (_currentToken.Type != TokenType.ParenthesisRight)
|
||||||
{
|
{
|
||||||
// 获取参数表达式
|
// 获取参数表达式
|
||||||
var arg = Expression();
|
//var arg = Expression();
|
||||||
_currentToken = _lexer.NextToken(); // consume arg
|
var arg = BooleanExpression();
|
||||||
|
_currentToken = _lexer.NextToken(); // 消耗参数 arg
|
||||||
arguments.Add(arg); // 添加到参数列表
|
arguments.Add(arg); // 添加到参数列表
|
||||||
if (_currentToken.Type == TokenType.Comma)
|
if (_currentToken.Type == TokenType.Comma)
|
||||||
{
|
{
|
||||||
_currentToken = _lexer.NextToken(); // consume ","
|
_currentToken = _lexer.NextToken(); // 消耗参数分隔符 ","
|
||||||
}
|
}
|
||||||
if (_currentToken.Type == TokenType.Semicolon)
|
if (_currentToken.Type == TokenType.Semicolon)
|
||||||
{
|
{
|
||||||
break; // consume ";"
|
break; // 消耗 ";"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -510,25 +800,37 @@ namespace Serein.Script
|
|||||||
|
|
||||||
_currentToken = _lexer.NextToken(); // consume "("
|
_currentToken = _lexer.NextToken(); // consume "("
|
||||||
|
|
||||||
var arguments = new List<ASTNode>();
|
|
||||||
bool isBreak = false;
|
bool isBreak = false;
|
||||||
while (_currentToken.Type != TokenType.ParenthesisRight)
|
var arguments = new List<ASTNode>();
|
||||||
|
// 获取参数
|
||||||
|
while (true)// _currentToken.Type != TokenType.ParenthesisRight
|
||||||
{
|
{
|
||||||
var arg = Expression(); // 获取参数表达式
|
//var arg = Expression(); // 获取参数表达式
|
||||||
_currentToken = _lexer.NextToken(); // consume arg
|
var arg = BooleanExpression(); // 获取参数表达式
|
||||||
arguments.Add(arg);
|
arguments.Add(arg);
|
||||||
if (_currentToken.Type == TokenType.Comma)
|
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 ";"
|
break; // consume ";"
|
||||||
}
|
}
|
||||||
|
/*if (_currentToken.Type == TokenType.Semicolon) // 提前结束
|
||||||
|
{
|
||||||
|
arguments.Add(arg);
|
||||||
|
isBreak = true;
|
||||||
|
break; // consume ";"
|
||||||
|
}*/
|
||||||
|
//_currentToken = _lexer.NextToken(); // consume arg
|
||||||
}
|
}
|
||||||
if(!isBreak)
|
//if(!isBreak)
|
||||||
_currentToken = _lexer.NextToken(); // consume ")"
|
// _currentToken = _lexer.NextToken(); // consume ")"
|
||||||
|
|
||||||
|
|
||||||
//var node = Statements[^1];
|
//var node = Statements[^1];
|
||||||
@@ -559,7 +861,8 @@ namespace Serein.Script
|
|||||||
{
|
{
|
||||||
return new ReturnNode().SetTokenInfo(_currentToken); // 返回空的 ReturnNode
|
return new ReturnNode().SetTokenInfo(_currentToken); // 返回空的 ReturnNode
|
||||||
}
|
}
|
||||||
var resultValue = Expression(); // 获取返回值表达式
|
var resultValue = BooleanExpression(); // 获取返回值表达式
|
||||||
|
//var resultValue = Expression(); // 获取返回值表达式
|
||||||
_currentToken = _lexer.NextToken();
|
_currentToken = _lexer.NextToken();
|
||||||
return new ReturnNode(resultValue).SetTokenInfo(_currentToken);
|
return new ReturnNode(resultValue).SetTokenInfo(_currentToken);
|
||||||
}
|
}
|
||||||
@@ -574,7 +877,8 @@ namespace Serein.Script
|
|||||||
{
|
{
|
||||||
_currentToken = _lexer.NextToken(); // Consume "if"
|
_currentToken = _lexer.NextToken(); // Consume "if"
|
||||||
_currentToken = _lexer.NextToken(); // Consume "("
|
_currentToken = _lexer.NextToken(); // Consume "("
|
||||||
ASTNode condition = Expression();
|
ASTNode condition = BooleanExpression();
|
||||||
|
//ASTNode condition = Expression();
|
||||||
_currentToken = _lexer.NextToken(); // Consume ")"
|
_currentToken = _lexer.NextToken(); // Consume ")"
|
||||||
|
|
||||||
// 确保遇到左大括号 { 后进入代码块解析
|
// 确保遇到左大括号 { 后进入代码块解析
|
||||||
@@ -590,6 +894,10 @@ namespace Serein.Script
|
|||||||
while (_currentToken.Type != TokenType.BraceRight && _currentToken.Type != TokenType.EOF)
|
while (_currentToken.Type != TokenType.BraceRight && _currentToken.Type != TokenType.EOF)
|
||||||
{
|
{
|
||||||
var astNode = Statement(); // 解析 if 分支中的语句
|
var astNode = Statement(); // 解析 if 分支中的语句
|
||||||
|
while (_currentToken.Type == TokenType.Semicolon)
|
||||||
|
{
|
||||||
|
_currentToken = _lexer.NextToken();
|
||||||
|
}
|
||||||
if (astNode != null)
|
if (astNode != null)
|
||||||
{
|
{
|
||||||
trueBranch.Add(astNode); // 将 if 分支的语句添加到 trueBranch 中
|
trueBranch.Add(astNode); // 将 if 分支的语句添加到 trueBranch 中
|
||||||
@@ -608,6 +916,10 @@ namespace Serein.Script
|
|||||||
while (_currentToken.Type != TokenType.BraceRight && _currentToken.Type != TokenType.EOF)
|
while (_currentToken.Type != TokenType.BraceRight && _currentToken.Type != TokenType.EOF)
|
||||||
{
|
{
|
||||||
var astNode = Statement(); // 解析 else 分支中的语句
|
var astNode = Statement(); // 解析 else 分支中的语句
|
||||||
|
while (_currentToken.Type == TokenType.Semicolon)
|
||||||
|
{
|
||||||
|
_currentToken = _lexer.NextToken();
|
||||||
|
}
|
||||||
if (astNode != null)
|
if (astNode != null)
|
||||||
{
|
{
|
||||||
falseBranch.Add(astNode); // 将 else 分支的语句添加到 falseBranch 中
|
falseBranch.Add(astNode); // 将 else 分支的语句添加到 falseBranch 中
|
||||||
@@ -633,7 +945,8 @@ namespace Serein.Script
|
|||||||
{
|
{
|
||||||
_currentToken = _lexer.NextToken(); // Consume "while"
|
_currentToken = _lexer.NextToken(); // Consume "while"
|
||||||
_currentToken = _lexer.NextToken(); // Consume "("
|
_currentToken = _lexer.NextToken(); // Consume "("
|
||||||
ASTNode condition = Expression();
|
ASTNode condition = BooleanExpression();
|
||||||
|
//ASTNode condition = Expression();
|
||||||
_currentToken = _lexer.NextToken(); // Consume ")"
|
_currentToken = _lexer.NextToken(); // Consume ")"
|
||||||
_currentToken = _lexer.NextToken(); // Consume "{"
|
_currentToken = _lexer.NextToken(); // Consume "{"
|
||||||
List<ASTNode> body = new List<ASTNode>();
|
List<ASTNode> body = new List<ASTNode>();
|
||||||
@@ -645,43 +958,131 @@ namespace Serein.Script
|
|||||||
return new WhileNode(condition, body).SetTokenInfo(_currentToken);
|
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>
|
||||||
/// 解析表达式。
|
/// 顶层布尔表达式
|
||||||
|
/// </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>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private ASTNode Expression()
|
private ASTNode Expression()
|
||||||
{
|
{
|
||||||
ASTNode left = Term();
|
ASTNode left = Term();
|
||||||
while (_currentToken.Type == TokenType.Operator && (
|
|
||||||
_currentToken.Value == "+" || _currentToken.Value == "-" ||
|
while (_currentToken.Type == TokenType.Operator &&
|
||||||
_currentToken.Value == "*" || _currentToken.Value == "/"))
|
(_currentToken.Value == "+" || _currentToken.Value == "-"))
|
||||||
{
|
{
|
||||||
string op = _currentToken.Value.ToString();
|
string op = _currentToken.Value;
|
||||||
_currentToken = _lexer.NextToken();
|
_currentToken = _lexer.NextToken();
|
||||||
ASTNode right = Term();
|
ASTNode right = Term();
|
||||||
left = new BinaryOperationNode(left, op, right).SetTokenInfo(_currentToken);
|
left = new BinaryOperationNode(left, op, right).SetTokenInfo(_currentToken);
|
||||||
}
|
}
|
||||||
return left;
|
|
||||||
|
return left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 解析项(Term),用于处理加减乘除等运算符。
|
/// 乘除
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private ASTNode Term()
|
private ASTNode Term()
|
||||||
{
|
{
|
||||||
ASTNode left = Factor();
|
ASTNode left = Factor();
|
||||||
|
|
||||||
while (_currentToken.Type == TokenType.Operator &&
|
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();
|
_currentToken = _lexer.NextToken();
|
||||||
ASTNode right = Factor();
|
ASTNode right = Factor();
|
||||||
left = new BinaryOperationNode(left, op, right).SetTokenInfo(_currentToken);
|
left = new BinaryOperationNode(left, op, right).SetTokenInfo(_currentToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
return left;
|
return left;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -692,6 +1093,8 @@ namespace Serein.Script
|
|||||||
/// <exception cref="Exception"></exception>
|
/// <exception cref="Exception"></exception>
|
||||||
private ASTNode Factor()
|
private ASTNode Factor()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
#region 返回字面量
|
#region 返回字面量
|
||||||
if (_currentToken.Type == TokenType.Null)
|
if (_currentToken.Type == TokenType.Null)
|
||||||
{
|
{
|
||||||
@@ -757,11 +1160,122 @@ namespace Serein.Script
|
|||||||
}
|
}
|
||||||
#endregion
|
#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(); // 消耗 "("
|
_currentToken = _lexer.NextToken(); // 消耗 "("
|
||||||
var expr = Expression();
|
var expr = BooleanExpression();
|
||||||
|
//var expr = Expression();
|
||||||
if (_currentToken.Type != TokenType.ParenthesisRight)
|
if (_currentToken.Type != TokenType.ParenthesisRight)
|
||||||
throw new Exception("非预期的符号,预期符号为\")\"。");
|
throw new Exception("非预期的符号,预期符号为\")\"。");
|
||||||
_currentToken = _lexer.NextToken(); // 消耗 ")"
|
_currentToken = _lexer.NextToken(); // 消耗 ")"
|
||||||
@@ -775,38 +1289,10 @@ namespace Serein.Script
|
|||||||
return ParseObjectInstantiation();
|
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} " );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,51 +1,630 @@
|
|||||||
using Serein.Library.Utils;
|
using Serein.Library;
|
||||||
|
using Serein.Library.Utils;
|
||||||
using Serein.Script.Node;
|
using Serein.Script.Node;
|
||||||
using Serein.Script.Symbol;
|
using Serein.Script.Symbol;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reactive;
|
using System.Reactive;
|
||||||
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Serein.Script
|
namespace Serein.Script
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 脚本类型分析
|
||||||
|
/// </summary>
|
||||||
public class SereinScriptTypeAnalysis
|
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(); // 清空符号表
|
SymbolInfos.Clear(); // 清空符号表
|
||||||
|
|
||||||
|
// 初始化符号表
|
||||||
foreach (ASTNode astNode in programNode.Statements)
|
foreach (ASTNode astNode in programNode.Statements)
|
||||||
{
|
{
|
||||||
var type = Trace(astNode);
|
var type = Trace(astNode);
|
||||||
if (type is null) continue;
|
if (type is null) continue;
|
||||||
var info = Analyse(astNode, type);
|
var info = Analyse(astNode, type);
|
||||||
if(info != null)
|
if (info != null)
|
||||||
{
|
{
|
||||||
SymbolInfos[info.Name] = info;
|
SymbolInfos[info.Name] = info;
|
||||||
}
|
}
|
||||||
/*if(astNode is AssignmentNode assignmentNode)
|
}
|
||||||
{
|
|
||||||
var name = assignmentNode.Variable;
|
// 类型分析
|
||||||
var node = assignmentNode.Value;
|
foreach (ASTNode astNode in programNode.Statements)
|
||||||
var type = Analyse(node);
|
{
|
||||||
if(type is null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
var symbolInfo = new SymbolInfo
|
|
||||||
{
|
|
||||||
Type = type,
|
|
||||||
Node = node,
|
|
||||||
Name = name,
|
|
||||||
};
|
|
||||||
SymbolInfos[name] = symbolInfo;
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
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>
|
/// <summary>
|
||||||
/// 追踪类型
|
/// 追踪类型
|
||||||
@@ -71,12 +650,27 @@ namespace Serein.Script
|
|||||||
case CharNode charNode: // char
|
case CharNode charNode: // char
|
||||||
return typeof(char);
|
return typeof(char);
|
||||||
case IdentifierNode identifierNode: // 定义变量
|
case IdentifierNode identifierNode: // 定义变量
|
||||||
return typeof(object);
|
if(SymbolInfos.TryGetValue(identifierNode.Name, out var varSymbolInfo))
|
||||||
|
{
|
||||||
|
return varSymbolInfo.Type; // 返回定义的类型
|
||||||
|
}
|
||||||
|
return typeof(object); // 默认为 object
|
||||||
case AssignmentNode assignmentNode: // 赋值行为
|
case AssignmentNode assignmentNode: // 赋值行为
|
||||||
var type = Trace(assignmentNode.Value);
|
var targetType = Trace(assignmentNode.Target);
|
||||||
return type;
|
var valueType = Trace(assignmentNode.Value);
|
||||||
//throw new SereinSciptException(identifierNode, "尝试使用值为null的变量");
|
if (targetType.IsAssignableFrom(valueType))
|
||||||
//throw new SereinSciptException(identifierNode, "尝试使用未声明的变量");
|
{
|
||||||
|
if(assignmentNode.Target is IdentifierNode identifierNode
|
||||||
|
&& !SymbolInfos.ContainsKey(identifierNode.Name))
|
||||||
|
{
|
||||||
|
return valueType;
|
||||||
|
}
|
||||||
|
return targetType;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("无法转换类型");
|
||||||
|
}
|
||||||
case BinaryOperationNode binOpNode: // 递归计算二元操作
|
case BinaryOperationNode binOpNode: // 递归计算二元操作
|
||||||
var leftType = Trace(binOpNode.Left);
|
var leftType = Trace(binOpNode.Left);
|
||||||
var op = binOpNode.Operator;
|
var op = binOpNode.Operator;
|
||||||
@@ -84,18 +678,29 @@ namespace Serein.Script
|
|||||||
var resultType = BinaryOperationEvaluator.EvaluateType(leftType, op, rightType);
|
var resultType = BinaryOperationEvaluator.EvaluateType(leftType, op, rightType);
|
||||||
return resultType;
|
return resultType;
|
||||||
case ClassTypeDefinitionNode classTypeDefinitionNode:
|
case ClassTypeDefinitionNode classTypeDefinitionNode:
|
||||||
var definitionType = DynamicObjectHelper.CreateTypeWithProperties(classTypeDefinitionNode.Fields, classTypeDefinitionNode.ClassName, true);
|
var definitionType = DynamicObjectHelper.CreateTypeWithProperties(classTypeDefinitionNode.Fields, classTypeDefinitionNode.ClassName);
|
||||||
return definitionType;
|
return definitionType;
|
||||||
case ObjectInstantiationNode objectInstantiationNode: // 创建对象
|
case ObjectInstantiationNode objectInstantiationNode: // 创建对象
|
||||||
|
|
||||||
var typeName = objectInstantiationNode.TypeName;
|
var typeName = objectInstantiationNode.TypeName;
|
||||||
var objectType = Type.GetType(typeName);
|
var objectType = Type.GetType(typeName);
|
||||||
objectType ??= DynamicObjectHelper.GetCacheType(typeName);
|
objectType ??= DynamicObjectHelper.GetCacheType(typeName);
|
||||||
return objectType;
|
return objectType;
|
||||||
case FunctionCallNode callNode: // 调用方法
|
case FunctionCallNode callNode: // 调用方法
|
||||||
return null;
|
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: // 对象方法调用
|
case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用
|
||||||
return null;
|
var objectNode = memberFunctionCallNode.Object;
|
||||||
|
var objType = GetTypeOnMemberFunctionCallNode(objectNode);
|
||||||
|
var methodName = memberFunctionCallNode.FunctionName;
|
||||||
|
return GetMethodReturnType(objType, methodName);
|
||||||
case MemberAccessNode memberAccessNode: // 对象成员访问
|
case MemberAccessNode memberAccessNode: // 对象成员访问
|
||||||
var memberType = memberAccessNode.MemberName;
|
var memberType = memberAccessNode.MemberName;
|
||||||
return null;
|
return null;
|
||||||
@@ -110,7 +715,7 @@ namespace Serein.Script
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private SymbolInfo Analyse(ASTNode node, Type type)
|
private SymbolInfo Analyse(ASTNode node, Type type)
|
||||||
{
|
{
|
||||||
@@ -128,20 +733,32 @@ namespace Serein.Script
|
|||||||
Type = type,
|
Type = type,
|
||||||
};
|
};
|
||||||
case AssignmentNode assignmentNode: // 赋值行为
|
case AssignmentNode assignmentNode: // 赋值行为
|
||||||
return new SymbolInfo
|
if(assignmentNode.Target is IdentifierNode identifierNode1)
|
||||||
{
|
{
|
||||||
Name = assignmentNode.Variable,
|
return new SymbolInfo
|
||||||
Node = node,
|
{
|
||||||
Type = type,
|
Name = identifierNode1.Name,
|
||||||
};
|
Node = node,
|
||||||
|
Type = type,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case BinaryOperationNode binOpNode: // 递归计算二元操作
|
case BinaryOperationNode binOpNode: // 递归计算二元操作
|
||||||
|
break;
|
||||||
//case ClassTypeDefinitionNode classTypeDefinitionNode
|
//case ClassTypeDefinitionNode classTypeDefinitionNode
|
||||||
case ObjectInstantiationNode objectInstantiationNode: // 创建对象
|
case ObjectInstantiationNode objectInstantiationNode: // 创建对象
|
||||||
|
break;
|
||||||
case FunctionCallNode callNode: // 调用方法
|
case FunctionCallNode callNode: // 调用方法
|
||||||
|
break;
|
||||||
case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用
|
case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用
|
||||||
|
break;
|
||||||
case MemberAccessNode memberAccessNode: // 对象成员访问
|
case MemberAccessNode memberAccessNode: // 对象成员访问
|
||||||
|
break;
|
||||||
case CollectionIndexNode collectionIndexNode:
|
case CollectionIndexNode collectionIndexNode:
|
||||||
|
break;
|
||||||
case ReturnNode returnNode: // 返回内容
|
case ReturnNode returnNode: // 返回内容
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
//throw new SereinSciptException(node, $"解释器 EvaluateAsync() 未实现{node}节点行为");
|
//throw new SereinSciptException(node, $"解释器 EvaluateAsync() 未实现{node}节点行为");
|
||||||
@@ -150,24 +767,43 @@ namespace Serein.Script
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
#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;
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
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}");
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ namespace Serein.Script.Symbol
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 符号信息
|
/// 符号信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class SymbolInfo
|
public class SymbolInfo
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 符号名称
|
/// 符号名称
|
||||||
|
|||||||
Reference in New Issue
Block a user