暂时实现了简陋的脚本AST分析解释,后面再绑定到控件上

This commit is contained in:
fengjiayi
2024-12-20 23:39:29 +08:00
parent 114e81424b
commit ef119e11e3
52 changed files with 3175 additions and 261 deletions

View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Script.Node
{
public abstract class ASTNode
{
public string Code { get; private set; }
public int Row { get; private set; }
public int StartIndex { get; private set; }
public int Length { get; private set; }
internal ASTNode SetTokenInfo(Token token)
{
Row = token.Row;
StartIndex = token.StartIndex;
Length = token.Length;
Code = token.Code;
return this;
}
}
}

View File

@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Script.Node
{
/// <summary>
/// 变量节点
/// </summary>
public class AssignmentNode : ASTNode
{
public string Variable { get; }
public ASTNode Value { get; }
public AssignmentNode(string variable, ASTNode value) => (Variable, Value) = (variable, value);
}
}

View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Script.Node
{
/// <summary>
/// 二元表达式节点
/// </summary>
public class BinaryOperationNode : ASTNode
{
public ASTNode Left { get; }
public string Operator { get; }
public ASTNode Right { get; }
public BinaryOperationNode(ASTNode left, string op, ASTNode right)
{
Left = left;
Operator = op;
Right = right;
}
}
}

View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Script.Node
{
/// <summary>
/// 布尔字面量
/// </summary>
public class BooleanNode : ASTNode
{
public bool Value { get; }
public BooleanNode(bool value) => Value = value;
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Script.Node
{
/// <summary>
/// 动态类型定义
/// </summary>
public class ClassTypeDefinitionNode : ASTNode
{
public string ClassName { get; }
public Dictionary<string, Type> Fields { get; }
public ClassTypeDefinitionNode(Dictionary<string, Type> fields, string className)
{
this.Fields = fields;
this.ClassName = className;
}
}
}

View File

@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Script.Node
{
/// <summary>
/// 集合索引获取
/// </summary>
public class CollectionIndexNode : ASTNode
{
public ASTNode IndexValue { get; }
public CollectionIndexNode(ASTNode indexValue)
{
this.IndexValue = indexValue;
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Script.Node
{
/// <summary>
/// 挂载函数调用
/// </summary>
public class FunctionCallNode : ASTNode
{
public string FunctionName { get; }
public List<ASTNode> Arguments { get; }
public FunctionCallNode(string functionName, List<ASTNode> arguments)
{
FunctionName = functionName;
Arguments = arguments;
}
}
}

View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Script.Node
{
/// <summary>
/// 标识符(变量)
/// </summary>
public class IdentifierNode : ASTNode
{
public string Name { get; }
public IdentifierNode(string name) => Name = name;
}
}

View File

@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Script.Node
{
/// <summary>
/// 条件节点
/// </summary>
public class IfNode : ASTNode
{
public ASTNode Condition { get; }
public List<ASTNode> TrueBranch { get; }
public List<ASTNode> FalseBranch { get; }
public IfNode(ASTNode condition, List<ASTNode> trueBranch, List<ASTNode> falseBranch)
=> (Condition, TrueBranch, FalseBranch) = (condition, trueBranch, falseBranch);
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Script.Node
{
/// <summary>
/// 表示对象的成员访问
/// </summary>
public class MemberAccessNode : ASTNode
{
public ASTNode Object { get; }
public string MemberName { get; }
public MemberAccessNode(ASTNode obj, string memberName)
{
Object = obj;
MemberName = memberName;
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Script.Node
{
/// <summary>
/// 表示对对象成员的赋值
/// </summary>
public class MemberAssignmentNode : ASTNode
{
public ASTNode Object { get; }
public string MemberName { get; }
public ASTNode Value { get; }
public MemberAssignmentNode(ASTNode obj, string memberName, ASTNode value)
{
Object = obj;
MemberName = memberName;
Value = value;
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Script.Node
{
/// <summary>
/// 对象成员方法调用
/// </summary>
public class MemberFunctionCallNode : ASTNode
{
public ASTNode Object { get; }
public string FunctionName { get; }
public List<ASTNode> Arguments { get; }
public MemberFunctionCallNode(ASTNode @object, string functionName, List<ASTNode> arguments)
{
Object = @object;
FunctionName = functionName;
Arguments = arguments;
}
}
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Script.Node
{
/// <summary>
/// Null节点
/// </summary>
public class NullNode : ASTNode
{
}
}

View File

@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Script.Node
{
/// <summary>
/// 整数型字面量
/// </summary>
public class NumberNode : ASTNode
{
public int Value { get; }
public NumberNode(int value) => Value = value;
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Script.Node
{
/// <summary>
/// 类型创建
/// </summary>
public class ObjectInstantiationNode : ASTNode
{
public string TypeName { get; }
public List<ASTNode> Arguments { get; }
public ObjectInstantiationNode(string typeName, List<ASTNode> arguments)
{
this.TypeName = typeName;
this.Arguments = arguments;
}
}
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Script.Node
{
/// <summary>
/// 程序入口
/// </summary>
public class ProgramNode : ASTNode
{
public List<ASTNode> Statements { get; }
public ProgramNode(List<ASTNode> statements)
{
Statements = statements;
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Script.Node
{
/// <summary>
/// 返回值
/// </summary>
public class ReturnNode : ASTNode
{
public ASTNode Value { get; }
public ReturnNode(ASTNode returnNode)
{
Value = returnNode;
}
public ReturnNode()
{
}
}
}

View File

@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Script.Node
{
/// <summary>
/// 字符串字面量节点
/// </summary>
public class StringNode : ASTNode
{
public string Value { get; }
public StringNode(string input)
{
// 使用 StringBuilder 来构建输出
StringBuilder output = new StringBuilder(input.Length);
for (int i = 0; i < input.Length; i++)
{
if (i < input.Length - 1 && input[i] == '\\') // 找到反斜杠
{
char nextChar = input[i + 1];
// 处理转义符
switch (nextChar)
{
case 'r':
output.Append('\r');
i++; // 跳过 'r'
break;
case 'n':
output.Append('\n');
i++; // 跳过 'n'
break;
case 't':
output.Append('\t');
i++; // 跳过 't'
break;
case '\\': // 字面量反斜杠
output.Append('\\');
i++; // 跳过第二个 '\\'
break;
default:
output.Append(input[i]); // 不是转义符,保留反斜杠
break;
}
}
else
{
output.Append(input[i]); // 其他字符直接添加
}
}
Value = output.ToString();
}
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Script.Node
{
/// <summary>
/// 循环条件节点
/// </summary>
public class WhileNode : ASTNode
{
public ASTNode Condition { get; }
public List<ASTNode> Body { get; }
public WhileNode(ASTNode condition, List<ASTNode> body) => (Condition, Body) = (condition, body);
}
}

View File

@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Tool\**" />
<EmbeddedResource Remove="Tool\**" />
<None Remove="Tool\**" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Library\Serein.Library.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,532 @@
using Newtonsoft.Json.Linq;
using Serein.Library;
using Serein.Library.Api;
using Serein.Library.Utils;
using Serein.Script.Node;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Xml.Linq;
namespace Serein.Script
{
public sealed class SereinSciptException : Exception
{
//public ASTNode Node { get; }
public override string Message { get; }
public SereinSciptException(ASTNode node, string message)
{
//this.Node = node;
Message = $"异常信息 : {message} ,代码在第{node.Row}行: {node.Code.Trim()}";
}
}
public class SereinScriptInterpreter
{
/// <summary>
/// 定义的变量
/// </summary>
private Dictionary<string, object> _variables = new Dictionary<string, object>();
/// <summary>
/// 挂载的函数
/// </summary>
private static Dictionary<string, DelegateDetails> _functionTable = new Dictionary<string, DelegateDetails>();
/// <summary>
/// 挂载的函数调用的对象(用于函数需要实例才能调用的场景)
/// </summary>
private static Dictionary<string, Func<object>> _callFuncOfGetObjects = new Dictionary<string, Func<object>>();
/// <summary>
/// 定义的类型
/// </summary>
private static Dictionary<string, Type> _classDefinition = new Dictionary<string, Type>();
/// <summary>
/// 重置的变量
/// </summary>
public void ResetVar()
{
foreach (var nodeObj in _variables.Values)
{
if (nodeObj is not null)
{
if (typeof(IDisposable).IsAssignableFrom(nodeObj?.GetType()) && nodeObj is IDisposable disposable)
{
disposable?.Dispose();
}
}
else
{
}
}
_variables.Clear();
}
/// <summary>
/// 挂载函数
/// </summary>
/// <param name="functionName">函数名称</param>
/// <param name="methodInfo">方法信息</param>
public static void AddFunction(string functionName, MethodInfo methodInfo, Func<object>? callObj = null)
{
//if (!_functionTable.ContainsKey(functionName))
//{
// _functionTable[functionName] = new DelegateDetails(methodInfo);
//}
if(!methodInfo.IsStatic && callObj is null)
{
SereinEnv.WriteLine(InfoType.WARN, "函数挂载失败:试图挂载非静态的函数,但没有传入相应的获取实例的方法。");
return;
}
if(!methodInfo.IsStatic && callObj is not null)
{
// 静态函数不需要
_callFuncOfGetObjects.Add(functionName, callObj);
}
_functionTable[functionName] = new DelegateDetails(methodInfo);
}
/// <summary>
/// 挂载类型
/// </summary>
/// <param name="typeName">函数名称</param>
/// <param name="type">方法信息</param>
public static void AddClassType(Type type , string typeName = "")
{
if (string.IsNullOrEmpty(typeName))
{
typeName = type.Name;
}
if (!_classDefinition.ContainsKey(typeName))
{
_classDefinition[typeName] = type;
}
}
/// <summary>
/// 入口节点
/// </summary>
/// <param name="programNode"></param>
/// <returns></returns>
private async Task<object?> ExecutionProgramNodeAsync(ProgramNode programNode)
{
// 遍历 ProgramNode 中的所有语句并执行它们
foreach (var statement in programNode.Statements)
{
// 直接退出
if (statement is ReturnNode returnNode) // 遇到 Return 语句 提前退出
{
return await EvaluateAsync(statement);
}
else
{
await InterpretAsync(statement);
}
}
return null;
}
/// <summary>
/// 类型定义
/// </summary>
/// <param name="programNode"></param>
/// <returns></returns>
private void ExecutionClassTypeDefinitionNode(ClassTypeDefinitionNode classTypeDefinitionNode)
{
if (_classDefinition.ContainsKey(classTypeDefinitionNode.ClassName))
{
//SereinEnv.WriteLine(InfoType.WARN, $"异常信息 : 类型重复定义,代码在第{classTypeDefinitionNode.Row}行: {classTypeDefinitionNode.Code.Trim()}");
return;
}
var type = DynamicObjectHelper.CreateTypeWithProperties(classTypeDefinitionNode.Fields, classTypeDefinitionNode.ClassName);
_classDefinition[classTypeDefinitionNode.ClassName] = type; // 定义对象
}
/// <summary>
/// IF...ELSE... 语句块
/// </summary>
/// <param name="ifNode"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
private async Task ExecutionIfNodeAsync(IfNode ifNode)
{
var result = await EvaluateAsync(ifNode.Condition) ?? throw new SereinSciptException(ifNode, $"条件语句返回了 null");
if (result is not bool condition)
{
throw new SereinSciptException(ifNode, "条件语句返回值不为 bool 类型");
}
if (condition)
{
foreach (var trueNode in ifNode.TrueBranch)
{
await InterpretAsync(trueNode);
}
}
else
{
foreach (var falseNode in ifNode.FalseBranch)
{
await InterpretAsync(falseNode);
}
}
}
/// <summary>
/// WHILE(){...} 语句块
/// </summary>
/// <param name="whileNode"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
private async Task ExectutionWhileNodeAsync(WhileNode whileNode)
{
while (true)
{
var result = await EvaluateAsync(whileNode.Condition) ?? throw new SereinSciptException(whileNode, $"条件语句返回了 null");
if (result is not bool condition)
{
throw new SereinSciptException(whileNode, $"条件语句返回值不为 bool 类型(当前返回值类型为 {result.GetType()})");
}
if (!condition)
{
break;
}
foreach(var node in whileNode.Body)
{
await InterpretAsync(node);
}
}
}
/// <summary>
/// 操作节点
/// </summary>
/// <param name="assignmentNode"></param>
/// <returns></returns>
private async Task ExecutionAssignmentNodeAsync(AssignmentNode assignmentNode)
{
var tmp = await EvaluateAsync(assignmentNode.Value);
_variables[assignmentNode.Variable] = tmp;
}
private async Task<object> InterpretFunctionCallAsync(FunctionCallNode functionCallNode)
{
// 评估函数参数
var arguments = new object?[functionCallNode.Arguments.Count];
for (int i = 0; i < functionCallNode.Arguments.Count; i++)
{
ASTNode? arg = functionCallNode.Arguments[i];
arguments[i] = await EvaluateAsync(arg); // 评估每个参数
}
var funcName = functionCallNode.FunctionName;
object? instance = null; // 静态方法不需要传入实例所以可以传入null
// 查找并执行对应的函数
if (_functionTable.TryGetValue(funcName, out DelegateDetails? function))
{
if (!function.EmitMethodInfo.IsStatic)
{
if(_callFuncOfGetObjects.TryGetValue(funcName, out var action))
{
instance = action.Invoke();// 非静态的方法需要获取相应的实例
if (instance is null)
{
throw new SereinSciptException(functionCallNode, $"函数 {funcName} 尝试获取实例时返回了 null ");
}
}
else
{
throw new SereinSciptException(functionCallNode, $"挂载函数 {funcName} 时需要同时给定获取实例的 Func<object>");
}
}
var result = await function.InvokeAsync(instance,arguments);
return result;
}
else
{
throw new Exception($"Unknown function: {functionCallNode.FunctionName}");
}
}
public async Task<object?> InterpretAsync(ASTNode node)
{
if(node == null)
{
return null;
}
switch (node)
{
case ProgramNode programNode: // AST树入口
var scritResult = await ExecutionProgramNodeAsync(programNode);
return scritResult; // 遍历 ProgramNode 中的所有语句并执行它们
case ClassTypeDefinitionNode classTypeDefinitionNode: // 定义类型
ExecutionClassTypeDefinitionNode(classTypeDefinitionNode);
break;
case AssignmentNode assignment: // 出现在 = 右侧的表达式
await ExecutionAssignmentNodeAsync(assignment);
break;
case MemberAssignmentNode memberAssignmentNode: // 设置对象属性
await SetMemberValue(memberAssignmentNode);
break;
case MemberFunctionCallNode memberFunctionCallNode:
return await CallMemberFunction(memberFunctionCallNode);
break;
case IfNode ifNode: // 执行 if...else... 语句块
await ExecutionIfNodeAsync(ifNode);
break;
case WhileNode whileNode: // 循环语句块
await ExectutionWhileNodeAsync(whileNode);
break;
case FunctionCallNode functionCallNode: // 方法调用节点
return await InterpretFunctionCallAsync(functionCallNode);
case ReturnNode returnNode:
return await EvaluateAsync(returnNode);
default:
throw new SereinSciptException(node, "解释器 InterpretAsync() 未实现节点行为");
}
return null;
}
private async Task<object?> EvaluateAsync(ASTNode node)
{
if(node == null)
{
return null;
}
switch (node)
{
case NullNode nullNode:
return null;
case BooleanNode booleanNode:
return booleanNode.Value; // 返回数值
case NumberNode numberNode:
return numberNode.Value; // 返回数值
case StringNode stringNode:
return stringNode.Value; // 返回字符串值
case IdentifierNode identifierNode:
if (_variables.TryGetValue(identifierNode.Name, out var result))
{
//if(result == null)
//{
// throw new SereinSciptException(identifierNode, "尝试使用值为null的变量");
//}
return result; // 获取变量值
}
else
{
throw new SereinSciptException(identifierNode, "尝试使用未声明的变量");
}
case BinaryOperationNode binOpNode:
// 递归计算二元操作
var left = await EvaluateAsync(binOpNode.Left);
//if (left == null )
//{
// throw new SereinSciptException(binOpNode.Left, $"左值尝试使用 null");
//}
var right = await EvaluateAsync(binOpNode.Right);
//if (right == null)
//{
// throw new SereinSciptException(binOpNode.Right, "右值尝试使用计算 null");
//}
return EvaluateBinaryOperation(left, binOpNode.Operator, right);
case ObjectInstantiationNode objectInstantiationNode:
if (_classDefinition.TryGetValue(objectInstantiationNode.TypeName,out var type ))
{
object?[] args = new object[objectInstantiationNode.Arguments.Count];
for (int i = 0; i < objectInstantiationNode.Arguments.Count; i++)
{
var argNode = objectInstantiationNode.Arguments[i];
args[i] = await EvaluateAsync(argNode);
}
var obj = Activator.CreateInstance(type,args: args);// 创建对象
if (obj == null)
{
throw new SereinSciptException(objectInstantiationNode, $"类型创建失败\"{objectInstantiationNode.TypeName}\"");
}
return obj;
}
else
{
throw new SereinSciptException(objectInstantiationNode, $"使用了未定义的类型\"{objectInstantiationNode.TypeName}\"");
}
case FunctionCallNode callNode:
return await InterpretFunctionCallAsync(callNode); // 调用方法返回函数的返回值
case MemberAccessNode memberAccessNode:
return await GetValue(memberAccessNode);
case ReturnNode returnNode: //
return await EvaluateAsync(returnNode.Value); // 直接返回响应的内容
default:
throw new SereinSciptException(node, "解释器 EvaluateAsync() 未实现节点行为");
}
}
private object EvaluateBinaryOperation(object left, string op, object right)
{
// 根据运算符执行不同的运算
switch (op)
{
case "+":
if (left is string || right is string)
{
return left?.ToString() + right?.ToString(); // 字符串拼接
}
else if (left is int leftInt && right is int rightInt)
{
return leftInt + rightInt; // 整数加法
}
else if (left is long leftLong && right is long rightLong)
{
return leftLong + rightLong; // 整数加法
}
else if (left is double leftDouble && right is double rightDouble)
{
return leftDouble + rightDouble; // 整数加法
}
else
{
dynamic leftValue = Convert.ToDouble(left);
dynamic rightValue = Convert.ToDouble(right);
return leftValue + rightValue;
}
throw new Exception("Invalid types for + operator");
case "-":
return (int)left - (int)right;
case "*":
return (int)left * (int)right;
case "/":
return (int)left / (int)right;
case ">":
return (int)left > (int)right;
case "<":
return (int)left < (int)right;
case "==":
return Equals(left, right);
case "!=":
return !Equals(left, right);
default:
throw new NotImplementedException("未定义的操作符: " + op);
}
}
/// <summary>
/// 设置对象成员
/// </summary>
/// <param name="memberAssignmentNode"></param>
/// <returns></returns>
/// <exception cref="SereinSciptException"></exception>
public async Task SetMemberValue(MemberAssignmentNode memberAssignmentNode)
{
var target = await EvaluateAsync(memberAssignmentNode.Object);
var value = await EvaluateAsync(memberAssignmentNode.Value);
// 设置值
var lastMember = memberAssignmentNode.MemberName;
var lastProperty = target?.GetType().GetProperty(lastMember);
if (lastProperty is null)
{
var lastField = target?.GetType().GetRuntimeField(lastMember);
if (lastField is null)
{
throw new SereinSciptException(memberAssignmentNode, $"对象没有成员\"{memberAssignmentNode.MemberName}\"");
}
else
{
var convertedValue = Convert.ChangeType(value, lastField.FieldType);
lastField.SetValue(target, convertedValue);
}
}
else
{
var convertedValue = Convert.ChangeType(value, lastProperty.PropertyType);
lastProperty.SetValue(target, convertedValue);
}
}
/// <summary>
/// 获取对象成员
/// </summary>
/// <param name="memberAccessNode"></param>
/// <returns></returns>
/// <exception cref="SereinSciptException"></exception>
public async Task<object?> GetValue(MemberAccessNode memberAccessNode)
{
var target = await EvaluateAsync(memberAccessNode.Object);
var lastMember = memberAccessNode.MemberName;
var lastProperty = target?.GetType().GetProperty(lastMember);
if (lastProperty is null)
{
var lastField = target?.GetType().GetRuntimeField(lastMember);
if (lastField is null)
{
throw new SereinSciptException(memberAccessNode, $"对象没有成员\"{memberAccessNode.MemberName}\"");
}
else
{
return lastField.GetValue(target);
}
}
else
{
return lastProperty.GetValue(target);
}
}
/// <summary>
/// 缓存method委托
/// </summary>
private Dictionary<string, DelegateDetails> MethodToDelegateCaches { get; } = new Dictionary<string, DelegateDetails>();
public async Task<object?> CallMemberFunction(MemberFunctionCallNode memberFunctionCallNode)
{
var target = await EvaluateAsync(memberFunctionCallNode.Object);
var lastMember = memberFunctionCallNode.FunctionName;
var methodInfo = target?.GetType().GetMethod(lastMember) ?? throw new SereinSciptException(memberFunctionCallNode, $"对象没有方法\"{memberFunctionCallNode.FunctionName}\"");
if(!MethodToDelegateCaches.TryGetValue(methodInfo.Name, out DelegateDetails? delegateDetails))
{
delegateDetails = new DelegateDetails(methodInfo);
MethodToDelegateCaches[methodInfo.Name] = delegateDetails;
}
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(arg); // 评估每个参数
}
return await delegateDetails.InvokeAsync(target, arguments);
}
}
}

View File

@@ -0,0 +1,360 @@
using Newtonsoft.Json.Linq;
using System.Runtime.CompilerServices;
using System.Xml.Linq;
namespace Serein.Script
{
internal enum TokenType
{
/// <summary>
/// 预料之外的值
/// </summary>
Null,
/// <summary>
/// 标识符
/// </summary>
Identifier,
/// <summary>
/// 布尔
/// </summary>
Boolean,
/// <summary>
/// 数值
/// </summary>
Number,
/// <summary>
/// 字符串
/// </summary>
String,
/// <summary>
/// 关键字
/// </summary>
Keyword,
/// <summary>
/// 操作符
/// </summary>
Operator,
/// <summary>
/// 左小括号
/// </summary>
ParenthesisLeft,
/// <summary>
/// 右小括号
/// </summary>
ParenthesisRight,
/// <summary>
/// 左中括号
/// </summary>
SquareBracketsLeft,
/// <summary>
/// 右中括号
/// </summary>
SquareBracketsRight,
/// <summary>
/// 左大括号
/// </summary>
BraceLeft,
/// <summary>
/// 右大括号
/// </summary>
BraceRight,
/// <summary>
/// 点号
/// </summary>
Dot,
/// <summary>
/// 逗号
/// </summary>
Comma,
/// <summary>
/// 分号
/// </summary>
Semicolon,
/// <summary>
/// 行注释
/// </summary>
// RowComment,
/// <summary>
/// 解析完成
/// </summary>
EOF
}
internal ref struct Token
{
public TokenType Type { get; }
public string Value { get; }
public int Row { get; set; }
public string Code { get; set; }
public int StartIndex { get; set; }
public int Length { get; set; }
internal Token(TokenType type, string value)
{
Type = type;
Value = value;
}
}
internal ref struct SereinScriptLexer
{
private readonly ReadOnlySpan<char> _input;
private int _index;
private int _row ;
private string[] _keywords = [
"let",
"func",
"if",
"else",
"return",
"while",
"new",
"class",
];
internal SereinScriptLexer(string input)
{
_input = input.AsSpan();
_index = 0;
}
internal Token PeekToken()
{
int currentIndex = _index; // 保存当前索引
Token nextToken = NextToken(); // 获取下一个 token
_index = currentIndex; // 恢复索引到当前位置
return nextToken; // 返回下一个 token
}
internal Token NextToken()
{
// 跳过空白字符
while (_index < _input.Length && char.IsWhiteSpace(_input[_index]))
{
if (_input[_index] == '\n')
{
_row++;
}
_index++;
}
if (_index >= _input.Length) return new Token(TokenType.EOF, string.Empty);
char currentChar = _input[_index];
// 识别字符串字面量
if (currentChar == '"')
{
return ReadString();
}
// 跳过注释
if (_input[_index] == '/' && _input[_index + 1] == '/')
{
// 一直识别到换行符的出现
while (_index < _input.Length && _input[_index] != '\n')
{
_index++;
}
return NextToken(); // 跳过注释后返回下一个识别token
}
// 识别null字面量
if (currentChar == 'n')
{
if (_input[_index + 1] == 'u'
&& _input[_index + 2] == 'l'
&& _input[_index + 3] == 'l')
{
var value = _input.Slice(_index, 4).ToString();
return CreateToken(TokenType.Null, "null");
}
}
// 识别布尔字面量
if (currentChar == 't')
{
if (_input[_index + 1] == 'r'
&& _input[_index + 2] == 'u'
&& _input[_index + 3] == 'e')
{
return CreateToken(TokenType.Boolean, "true");
}
}
else if (currentChar == 'f')
{
if (_input[_index + 1] == 'a'
&& _input[_index + 2] == 'l'
&& _input[_index + 3] == 's'
&& _input[_index + 4] == 'e')
{
return CreateToken(TokenType.Boolean, "false");
}
}
// 识别数字
if (char.IsDigit(currentChar))
{
var start = _index;
while (_index < _input.Length && char.IsDigit(_input[_index]))
_index++;
var value = _input.Slice(start, _index - start).ToString();
_index = start; // 回退索引,索引必须只能在 CreateToken 方法内更新
return CreateToken(TokenType.Number, value);
}
// 识别标识符(变量名、关键字)
if (char.IsLetter(currentChar))
{
var start = _index;
while (_index < _input.Length && (char.IsLetterOrDigit(_input[_index]) || _input[_index] == '_'))
_index++;
var value = _input.Slice(start, _index - start).ToString();
_index = start; // 回退索引,索引必须只能在 CreateToken 方法内更新
return CreateToken(_keywords.Contains(value) ? TokenType.Keyword : TokenType.Identifier, value);
}
// 识别符号
switch (currentChar)
{
case '(': return CreateToken(TokenType.ParenthesisLeft, "(");
case ')': return CreateToken(TokenType.ParenthesisRight, ")");
case '[': return CreateToken(TokenType.SquareBracketsLeft, "[");
case ']': return CreateToken(TokenType.SquareBracketsRight, "]");
case '{': return CreateToken(TokenType.BraceLeft, "{");
case '}': return CreateToken(TokenType.BraceRight, "}");
case ',': return CreateToken(TokenType.Comma, ",");
case ';': return CreateToken(TokenType.Semicolon, ";");
case '+':
case '-':
case '*':
case '/':
return CreateToken(TokenType.Operator, currentChar.ToString());
case '>': // 识别 ">" 或 ">="
if (_index + 1 < _input.Length && _input[_index + 1] == '=')
{
return CreateToken(TokenType.Operator, ">=");
}
return CreateToken(TokenType.Operator, ">");
case '<': // 识别 "<" 或 "<="
if (_index + 1 < _input.Length && _input[_index + 1] == '=')
{
return CreateToken(TokenType.Operator, "<=");
}
return CreateToken(TokenType.Operator, "<");
case '!': // 识别 "!="
if (_index + 1 < _input.Length && _input[_index + 1] == '=')
{
return CreateToken(TokenType.Operator, "!=");
}
break;
case '=': // 识别 "=="
if (_index + 1 < _input.Length && _input[_index + 1] == '=')
{
return CreateToken(TokenType.Operator, "==");
}
else
{
return CreateToken(TokenType.Operator, "=");
}
case '.':
return CreateToken(TokenType.Dot, ".");
}
throw new Exception("Unexpected character: " + currentChar);
}
private Token CreateToken(TokenType tokenType, string value)
{
var code = GetLine(_row).ToString();
var token = new Token(tokenType, value)
{
Row = _row,
StartIndex = _index,
Length = value.Length,
Code = code,
};
_index += value.Length;
return token;
}
/// <summary>
/// 读取硬编码的文本
/// </summary>
/// <returns></returns>
/// <exception cref="Exception"></exception>
private Token ReadString()
{
_index++; // 跳过开头的引号
var start = _index;
while (_index < _input.Length && _input[_index] != '"')
{
if (_input[_index] == '\\' && _index + 1 < _input.Length && (_input[_index + 1] == '"' || _input[_index + 1] == '\\'))
{
// 处理转义字符
_index++;
}
_index++;
}
if (_index >= _input.Length) throw new Exception("Unterminated string literal");
var value = _input.Slice(start, _index - start).ToString();
// var value = _input.Substring(start, _index - start);
_index = start + 1; // 跳过引号
return CreateToken(TokenType.String, value);
// _index++; // 跳过结束的引号
//return new Token(TokenType.String, value.ToString());
}
/// <summary>
/// 获取对应行的代码文本
/// </summary>
/// <param name="lineNumber"></param>
/// <returns></returns>
private ReadOnlySpan<char> GetLine( int lineNumber)
{
ReadOnlySpan<char> text = _input;
int currentLine = 0;
int start = 0;
for (int i = 0; i < text.Length; i++)
{
if (text[i] == '\n') // 找到换行符
{
if (currentLine == lineNumber)
{
return text.Slice(start, i - start); // 返回从start到当前位置的行文本
}
currentLine++;
start = i + 1; // 下一行的起始位置
}
}
// 如果没有找到指定行返回空的Span
return ReadOnlySpan<char>.Empty;
}
}
}

View File

@@ -0,0 +1,647 @@
using Newtonsoft.Json.Linq;
using Serein.Library;
using Serein.Script.Node;
using System.Collections.Generic;
using System.Linq.Expressions;
namespace Serein.Script
{
public ref struct SereinScriptParser
{
private SereinScriptLexer _lexer;
private Token _currentToken;
public SereinScriptParser(string script)
{
_lexer = new SereinScriptLexer(script); // 语法分析
_currentToken = _lexer.NextToken();
}
public ASTNode Parse()
{
return Program();
}
private List<ASTNode> Statements { get; } = new List<ASTNode>();
private ASTNode Program()
{
Statements.Clear();
while (_currentToken.Type != TokenType.EOF)
{
var astNode = Statement();
if (astNode == null)
{
continue;
}
Statements.Add(astNode);
//if (astNode is ClassTypeDefinitionNode)
//{
// // 类型定义置顶
// statements = [astNode, ..statements];
//}
//else
//{
// statements.Add(astNode);
//}
}
return new ProgramNode(Statements).SetTokenInfo(_currentToken);
}
private ASTNode Statement()
{
if (_currentToken.Type == TokenType.Keyword && _currentToken.Value == "let")
{
return ParseLetAssignment();
}
if (_currentToken.Type == TokenType.Keyword && _currentToken.Value == "class")
{
return ParseClassDefinition();
}
if (_currentToken.Type == TokenType.Keyword && _currentToken.Value == "if")
{
return ParseIf();
}
if (_currentToken.Type == TokenType.Keyword && _currentToken.Value == "while")
{
return ParseWhile();
}
if (_currentToken.Type == TokenType.Keyword && _currentToken.Value == "return")
{
return ParseReturn();
}
if (_currentToken.Type == TokenType.Identifier)
{
return ParseIdentifier();
}
if (_currentToken.Type == TokenType.Null)
{
return Expression();
}
// 处理其他语句(如表达式语句等)
if (_currentToken.Type == TokenType.Semicolon)
{
_currentToken = _lexer.NextToken();
return null; // 表示空语句
}
throw new Exception("Unexpected statement: " + _currentToken.Value.ToString());
}
/// <summary>
/// 从标识符解析方法调用、变量赋值、获取对象成员行为。
/// (非符号、关键字)
/// </summary>
/// <returns></returns>
private ASTNode ParseIdentifier()
{
// 检查标识符后是否跟有左圆括号
var _tempToken = _lexer.PeekToken();
if (_tempToken.Type == TokenType.ParenthesisLeft)
{
// 解析函数调用
return ParseFunctionCall();
}
else if (_tempToken.Type == TokenType.Dot)
{
// 对象成员的获取
return ParseMemberAccessOrAssignment();
}
else
{
// 不是函数调用,是变量赋值或其他
return ParseAssignment();
}
}
/// <summary>
/// 解析赋值行为
/// </summary>
/// <returns></returns>
/// <exception cref="Exception"></exception>
private ASTNode ParseAssignment()
{
string variableName = _currentToken.Value.ToString();
_currentToken = _lexer.NextToken(); // consume identifier
if(_currentToken.Type == TokenType.ParenthesisRight)
{
return new IdentifierNode(variableName).SetTokenInfo(_currentToken);
}
if(_currentToken.Type == TokenType.Operator && _currentToken.Value == "=")
{
// 赋值行为
_currentToken = _lexer.NextToken(); // consume "="
var _tempToken = _lexer.PeekToken();
ASTNode valueNode;
if (_tempToken.Type == TokenType.ParenthesisLeft)
{
// 解析赋值右边的表达式
// 是函数调用,解析函数调用
valueNode = ParseFunctionCall();
}
else
{
// 解析赋值右边的字面量表达式
valueNode = Expression();
}
return new AssignmentNode(variableName, valueNode).SetTokenInfo(_currentToken);
}
if (_currentToken.Type == TokenType.Dot)
{
return ParseMemberAccessOrAssignment();
}
throw new Exception($"Expected '{_currentToken.Value}' after variable name");
}
/// <summary>
/// 解析 let 变量赋值行为
/// </summary>
/// <returns></returns>
/// <exception cref="Exception"></exception>
private ASTNode ParseLetAssignment()
{
_currentToken = _lexer.NextToken(); // Consume "let"
string variable = _currentToken.Value.ToString();
_currentToken = _lexer.NextToken(); // Consume identifier
ASTNode value;
if (_currentToken.Type == TokenType.Semicolon)
{
// 定义一个变量,初始值为 null
value = new NullNode();
}
else
{
if (_currentToken.Type != TokenType.Operator || _currentToken.Value != "=")
throw new Exception("Expected '=' after variable name");
_currentToken = _lexer.NextToken();
value = Expression();
_currentToken = _lexer.NextToken(); // Consume semicolon
}
return new AssignmentNode(variable, value).SetTokenInfo(_currentToken);
}
private ASTNode ParseClassDefinition()
{
_currentToken = _lexer.NextToken(); // 消耗 class 关键字
var className = _currentToken.Value.ToString(); // 获取定义的类名
_currentToken = _lexer.NextToken(); // 消耗括号
if (_currentToken.Type != TokenType.BraceLeft || _currentToken.Value != "{")
throw new Exception("Expected '{' after class definition");
var classFields = new Dictionary<string, Type>();
_currentToken = _lexer.NextToken();
while (_currentToken.Type != TokenType.BraceRight)
{
var fieldType = _currentToken.Value.ToString().ToTypeOfString(); // 获取定义的类名
_currentToken = _lexer.NextToken();
var fieldName = _currentToken.Value.ToString(); // 获取定义的类名
_currentToken = _lexer.NextToken();
classFields.Add(fieldName,fieldType);
if (_currentToken.Type == TokenType.Semicolon && _lexer.PeekToken().Type == TokenType.BraceRight)
{
break;
}
else
{
_currentToken = _lexer.NextToken();
}
}
_currentToken = _lexer.NextToken();
_currentToken = _lexer.NextToken();
return new ClassTypeDefinitionNode(classFields, className).SetTokenInfo(_currentToken);
}
public ASTNode ParseObjectInstantiation()
{
_currentToken = _lexer.NextToken(); // Consume "new"
string typeName = _currentToken.Value.ToString(); // Get type name
_currentToken = _lexer.NextToken();
if (_currentToken.Type != TokenType.ParenthesisLeft)
throw new Exception("Expected '(' after function name");
_currentToken = _lexer.NextToken(); // consume "("
var arguments = new List<ASTNode>();
while (_currentToken.Type != TokenType.ParenthesisRight)
{
arguments.Add(Expression());
if (_currentToken.Type == TokenType.Comma)
{
_currentToken = _lexer.NextToken(); // consume ","
}
}
_currentToken = _lexer.NextToken(); // consume ")"
return new ObjectInstantiationNode(typeName, arguments).SetTokenInfo(_currentToken);
}
public ASTNode ParseCollectionIndex()
{
string functionName = _currentToken.Value.ToString();
_currentToken = _lexer.NextToken(); // consume identifier
if (_currentToken.Type != TokenType.ParenthesisLeft)
throw new Exception("Expected '[' after function name");
_currentToken = _lexer.NextToken(); // consume "["
ASTNode indexValue = Expression(); // get index value
_currentToken = _lexer.NextToken(); // consume "]"
return new CollectionIndexNode(indexValue).SetTokenInfo(_currentToken);
}
/// <summary>
/// 获取对象成员
/// </summary>
/// <returns></returns>
/// <exception cref="Exception"></exception>
private ASTNode ParseMemberAccessOrAssignment()
{
var identifierNode = new IdentifierNode(_currentToken.Value).SetTokenInfo(_currentToken);
_currentToken = _lexer.NextToken(); // 消耗当前标识符
// 处理成员访问identifier.member
if (_currentToken.Type == TokenType.Dot)
{
_currentToken = _lexer.NextToken(); // 消耗 "."
if (_currentToken.Type != TokenType.Identifier)
{
throw new Exception("Expected member name after dot.");
}
var memberName = _currentToken.Value;
//_currentToken = _lexer.NextToken(); // 消耗成员名
var _peekToken = _lexer.PeekToken();
if (_peekToken.Type == TokenType.Operator && _peekToken.Value == "=")
{
// 成员赋值 obj.Member = xxx;
_currentToken = _lexer.NextToken(); // 消耗 "="
_currentToken = _lexer.NextToken(); // 消耗 "="
var valueNode = Expression(); // 解析右值
return new MemberAssignmentNode(identifierNode, memberName, valueNode).SetTokenInfo(_peekToken);
}
else
{
if(_peekToken.Type == TokenType.ParenthesisLeft)
{
// 成员方法调用 obj.Member(xxx);
return ParseMemberFunctionCall(identifierNode);
}
else if (_peekToken.Type == TokenType.SquareBracketsLeft)
{
// 数组 index; 字典 key obj.Member[xxx];
return ParseCollectionIndex();
}
else
{
// 成员获取
return new MemberAccessNode(identifierNode, memberName).SetTokenInfo(_currentToken);
}
}
}
return identifierNode;
}
private ASTNode ParseMemberFunctionCall(ASTNode targetNode)
{
string functionName = _currentToken.Value.ToString();
_currentToken = _lexer.NextToken(); // consume identifier
if (_currentToken.Type != TokenType.ParenthesisLeft)
throw new Exception("Expected '(' after function name");
_currentToken = _lexer.NextToken(); // consume "("
var arguments = new List<ASTNode>();
while (_currentToken.Type != TokenType.ParenthesisRight)
{
var arg = Expression();
_currentToken = _lexer.NextToken(); // consume arg
arguments.Add(arg);
if (_currentToken.Type == TokenType.Comma)
{
_currentToken = _lexer.NextToken(); // consume ","
}
if (_currentToken.Type == TokenType.Semicolon)
{
break; // consume ";"
}
}
_currentToken = _lexer.NextToken(); // consume ")"
return new MemberFunctionCallNode(targetNode, functionName, arguments).SetTokenInfo(_currentToken);
}
private ASTNode ParseFunctionCall()
{
string functionName = _currentToken.Value.ToString();
_currentToken = _lexer.NextToken(); // consume identifier
if (_currentToken.Type != TokenType.ParenthesisLeft)
throw new Exception("Expected '(' after function name");
_currentToken = _lexer.NextToken(); // consume "("
var arguments = new List<ASTNode>();
while (_currentToken.Type != TokenType.ParenthesisRight)
{
var arg = Expression();
_currentToken = _lexer.NextToken(); // consume arg
arguments.Add(arg);
if (_currentToken.Type == TokenType.Comma)
{
_currentToken = _lexer.NextToken(); // consume ","
}
if (_currentToken.Type == TokenType.Semicolon)
{
break; // consume ";"
}
}
_currentToken = _lexer.NextToken(); // consume ")"
//var node = Statements[^1];
//if (node is MemberAccessNode memberAccessNode)
//{
// // 上一个是对象
// return new MemberFunctionCallNode(memberAccessNode, functionName, arguments).SetTokenInfo(_currentToken);
//}
//if (node is IdentifierNode identifierNode)
//{
// return new MemberFunctionCallNode(identifierNode, functionName, arguments).SetTokenInfo(_currentToken);
//}
// 从挂载的函数表寻找对应的函数,尝试调用
return new FunctionCallNode(functionName, arguments).SetTokenInfo(_currentToken);
}
public ASTNode ParseReturn()
{
_currentToken = _lexer.NextToken();
if(_currentToken.Type == TokenType.Semicolon)
{
return new ReturnNode().SetTokenInfo(_currentToken);
}
var resultValue = Expression();
_currentToken = _lexer.NextToken();
return new ReturnNode(resultValue).SetTokenInfo(_currentToken);
}
private ASTNode ParseIf()
{
_currentToken = _lexer.NextToken(); // Consume "if"
_currentToken = _lexer.NextToken(); // Consume "("
ASTNode condition = Expression();
_currentToken = _lexer.NextToken(); // Consume ")"
// 确保遇到左大括号 { 后进入代码块解析
if (_currentToken.Type != TokenType.BraceLeft)
{
throw new Exception("Expected '{' after if condition");
}
_currentToken = _lexer.NextToken(); // Consume "{"
// 解析大括号中的语句
List<ASTNode> trueBranch = new List<ASTNode>();
List<ASTNode> falseBranch = new List<ASTNode>();
while (_currentToken.Type != TokenType.BraceRight && _currentToken.Type != TokenType.EOF)
{
var astNode = Statement();
if (astNode != null)
{
trueBranch.Add(astNode);
}
}
// 确保匹配右大括号 }
if (_currentToken.Type != TokenType.BraceRight)
{
throw new Exception("Expected '}' after if block");
}
_currentToken = _lexer.NextToken(); // Consume "}"
if (_currentToken.Type == TokenType.Keyword && _currentToken.Value == "else")
{
_currentToken = _lexer.NextToken(); // Consume "{"
_currentToken = _lexer.NextToken(); // Consume "{"
while (_currentToken.Type != TokenType.BraceRight && _currentToken.Type != TokenType.EOF)
{
var astNode = Statement();
if (astNode != null)
{
falseBranch.Add(astNode);
}
}
// 确保匹配右大括号 }
if (_currentToken.Type != TokenType.BraceRight)
{
throw new Exception("Expected '}' after if block");
}
_currentToken = _lexer.NextToken(); // Consume "}"
}
return new IfNode(condition, trueBranch, falseBranch).SetTokenInfo(_currentToken);
}
private ASTNode ParseWhile()
{
_currentToken = _lexer.NextToken(); // Consume "while"
_currentToken = _lexer.NextToken(); // Consume "("
ASTNode condition = Expression();
_currentToken = _lexer.NextToken(); // Consume ")"
_currentToken = _lexer.NextToken(); // Consume "{"
List<ASTNode> body = new List<ASTNode>();
while (_currentToken.Type != TokenType.BraceRight)
{
body.Add(Statement());
}
_currentToken = _lexer.NextToken(); // Consume "}"
return new WhileNode(condition, body).SetTokenInfo(_currentToken);
}
private ASTNode Expression()
{
ASTNode left = Term();
while (_currentToken.Type == TokenType.Operator && (
_currentToken.Value == "+" || _currentToken.Value == "-" ||
_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;
}
private ASTNode Term()
{
ASTNode left = Factor();
while (_currentToken.Type == TokenType.Operator &&
(_currentToken.Value == "<" || _currentToken.Value == ">" ||
_currentToken.Value == "<=" || _currentToken.Value == ">=" ||
_currentToken.Value == "==" || _currentToken.Value == "!="))
{
string op = _currentToken.Value.ToString();
_currentToken = _lexer.NextToken();
ASTNode right = Factor();
left = new BinaryOperationNode(left, op, right).SetTokenInfo(_currentToken);
}
return left;
}
private ASTNode Factor()
{
#region
if (_currentToken.Type == TokenType.Null)
{
_currentToken = _lexer.NextToken(); // 消耗 null
return new NullNode().SetTokenInfo(_currentToken);
}
if (_currentToken.Type == TokenType.Boolean)
{
var value = bool.Parse(_currentToken.Value);
_currentToken = _lexer.NextToken(); // 消耗布尔量
return new BooleanNode(value).SetTokenInfo(_currentToken);
}
if (_currentToken.Type == TokenType.String)
{
var text = _currentToken.Value;
_currentToken = _lexer.NextToken(); // 消耗数字
return new StringNode(text.ToString()).SetTokenInfo(_currentToken);
}
if (_currentToken.Type == TokenType.Number)
{
var value = int.Parse(_currentToken.Value);
_currentToken = _lexer.NextToken(); // 消耗数字
return new NumberNode(value).SetTokenInfo(_currentToken);
}
#endregion
// 方法调用
if (_currentToken.Type == TokenType.ParenthesisLeft)
{
_currentToken = _lexer.NextToken(); // 消耗 "("
var expr = Expression();
if (_currentToken.Type != TokenType.ParenthesisRight)
throw new Exception("非预期的符号,预期符号为\")\"。");
_currentToken = _lexer.NextToken(); // 消耗 ")"
return expr;
}
// 创建对象
if (_currentToken.Type == TokenType.Keyword && _currentToken.Value == "new")
{
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();
var identifierNode = new IdentifierNode(identifier).SetTokenInfo(_currentToken);
// 处理成员访问identifier.member
if (_currentToken.Type == TokenType.Dot)
{
_currentToken = _lexer.NextToken(); // 消耗 "."
if (_currentToken.Type != TokenType.Identifier)
{
throw new Exception("Expected member name after dot.");
}
var memberName = _currentToken.Value;
_currentToken = _lexer.NextToken(); // 消耗成员名
if (_currentToken.Type == TokenType.Operator && _currentToken.Value == "=")
{
// 成员赋值 obj.Member = xxx;
_currentToken = _lexer.NextToken(); // 消耗 "="
var valueNode = Expression(); // 解析右值
return new MemberAssignmentNode(identifierNode, memberName, valueNode).SetTokenInfo(_currentToken);
}
else
{
var _peekToken = _lexer.PeekToken();
if (_peekToken.Type == TokenType.ParenthesisLeft)
{
// 成员方法调用 obj.Member(xxx);
return ParseFunctionCall();
}
else if (_peekToken.Type == TokenType.SquareBracketsLeft)
{
// 数组 index; 字典 key obj.Member[xxx];
return ParseCollectionIndex();
}
else
{
// 成员获取
return new MemberAccessNode(identifierNode, memberName).SetTokenInfo(_currentToken);
}
}
}
return identifierNode;
}
_currentToken = _lexer.NextToken(); // 消耗标识符
return new IdentifierNode(identifier.ToString()).SetTokenInfo(_currentToken);
}
throw new Exception("Unexpected factor: " + _currentToken.Value.ToString());
}
}
}

View File

@@ -0,0 +1,119 @@
using Serein.Library.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using static Serein.Library.Utils.EmitHelper;
namespace Serein.Library
{
/// <summary>
/// Emit创建的委托描述用于WebApi、WebSocket、NodeFlow动态调用方法的场景。
/// 一般情况下你无须关注内部细节,只需要调用 Invoke() 方法即可。
/// </summary>
public class DelegateDetails
{
/// <summary>
/// 根据方法信息构建Emit委托
/// </summary>
/// <param name="methodInfo"></param>
public DelegateDetails(MethodInfo methodInfo)
{
var emitMethodType = EmitHelper.CreateDynamicMethod(methodInfo, out var emitDelegate);
_emitMethodInfo = emitMethodType;
_emitDelegate = emitDelegate;
}
/*/// <summary>
/// 更新委托方法
/// </summary>
/// <param name="EmitMethodType"></param>
/// <param name="EmitDelegate"></param>
public void Upload(EmitMethodType EmitMethodType, Delegate EmitDelegate)
{
_emitMethodType = EmitMethodType;
_emitDelegate = EmitDelegate;
}*/
private Delegate _emitDelegate;
private EmitMethodInfo _emitMethodInfo;
///// <summary>
///// <para>普通方法Func&lt;object,object[],object&gt;</para>
///// <para>异步方法Func&lt;object,object[],Task&gt;</para>
///// <para>异步有返回值方法Func&lt;object,object[],Task&lt;object&gt;&gt;</para>
///// </summary>
//public Delegate EmitDelegate { get => _emitDelegate; }
///// <summary>
///// 表示Emit构造的委托类型
///// </summary>
//public EmitMethodType EmitMethodType { get => _emitMethodType; }
public async Task<object> AutoInvokeAsync(object[] args)
{
if (_emitMethodInfo.IsStatic)
{
return await InvokeAsync(null, args);
}
else
{
var obj = Activator.CreateInstance(_emitMethodInfo.DeclaringType);
return await InvokeAsync(obj, args);
}
throw new Exception("Not static method");
}
/// <summary>
/// <para>使用的实例必须能够正确调用该委托,传入的参数也必须符合方法入参信息。</para>
/// </summary>
/// <param name="instance">拥有符合委托签名的方法信息的实例</param>
/// <param name="args">如果方法没有入参,也需要传入一个空数组</param>
/// <returns>void方法自动返回null</returns>
public async Task<object> InvokeAsync(object instance, object[] args)
{
if (args is null)
{
args = Array.Empty<object>();
}
if(_emitMethodInfo.IsStatic)
{
instance = null;
}
object result = null;
if (_emitDelegate is Func<object, object[], Task<object>> hasResultTask)
{
result = await hasResultTask(instance, args);
}
else if (_emitDelegate is Func<object, object[], Task> task)
{
await task.Invoke(instance, args);
}
else if (_emitDelegate is Func<object, object[], object> func)
{
result = func.Invoke(instance, args);
}
else
{
throw new NotImplementedException("创建了非预期委托(应该不会出现)");
}
//
return result;
//try
//{
//}
//catch
//{
// throw;
//}
}
}
}

View File

@@ -0,0 +1,203 @@
using System.Reflection;
using System.Reflection.Emit;
namespace Serein.Library.Utils
{
/// <summary>
/// Emit创建委托工具类
/// </summary>
public class EmitHelper
{
public class EmitMethodInfo
{
public Type DeclaringType { get; set; }
/// <summary>
/// 是异步方法
/// </summary>
public bool IsTask { get; set; }
/// <summary>
/// 是静态的
/// </summary>
public bool IsStatic { get; set; }
}
public enum EmitMethodType
{
/// <summary>
/// 普通的方法。如果方法返回void时将会返回null。
/// </summary>
Func,
/// <summary>
/// 无返回值的异步方法
/// </summary>
Task,
/// <summary>
/// 有返回值的异步方法
/// </summary>
HasResultTask,
/// <summary>
/// 普通的方法。如果方法返回void时将会返回null。
/// </summary>
StaticFunc,
/// <summary>
/// 无返回值的异步方法
/// </summary>
StaticTask,
}
public static bool IsGenericTask(Type returnType, out Type taskResult)
{
// 判断是否为 Task 类型或泛型 Task<T>
if (returnType == typeof(Task))
{
taskResult = null;
return true;
}
else if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>))
{
// 获取泛型参数类型
Type genericArgument = returnType.GetGenericArguments()[0];
taskResult = genericArgument;
return true;
}
else
{
taskResult = null;
return false;
}
}
/// <summary>
/// 根据方法信息创建动态调用的委托,返回方法类型,以及传出一个委托
/// </summary>
/// <param name="methodInfo"></param>
/// <param name="delegate"></param>
/// <returns></returns>
public static EmitMethodInfo CreateDynamicMethod(MethodInfo methodInfo,out Delegate @delegate)
{
EmitMethodInfo emitMethodInfo = new EmitMethodInfo();
bool IsTask = IsGenericTask(methodInfo.ReturnType, out var taskGenericsType);
bool IsTaskGenerics = taskGenericsType != null;
DynamicMethod dynamicMethod;
Type returnType;
if (!IsTask)
{
// 普通方法
returnType = typeof(object);
}
else
{
// 异步方法
if (IsTaskGenerics)
{
returnType = typeof(Task<object>);
}
else
{
returnType = typeof(Task);
}
}
dynamicMethod = new DynamicMethod(
name: methodInfo.Name + "_DynamicEmitMethod",
returnType: returnType,
parameterTypes: new[] { typeof(object), typeof(object[]) }, // 方法实例、方法入参
restrictedSkipVisibility: true // 跳过私有方法访问限制
);
var il = dynamicMethod.GetILGenerator();
// 判断是否为静态方法
bool isStatic = methodInfo.IsStatic;
if (isStatic)
{
// 如果是静态方法直接跳过实例不加载Ldarg_0
}
else
{
// 加载实例 (this) 对于非静态方法
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, methodInfo.DeclaringType); // 将 ISocketControlBase 转换为目标类类型
}
// 加载方法参数
var methodParams = methodInfo.GetParameters();
for (int i = 0; i < methodParams.Length; i++)
{
il.Emit(OpCodes.Ldarg_1); // 加载参数数组
il.Emit(OpCodes.Ldc_I4, i); // 加载当前参数索引
il.Emit(OpCodes.Ldelem_Ref); // 取出数组元素
var paramType = methodParams[i].ParameterType;
if (paramType.IsValueType) // 如果参数是值类型,拆箱
{
il.Emit(OpCodes.Unbox_Any, paramType);
}
//else if (paramType.IsGenericParameter) // 如果是泛型参数,直接转换
//{
// il.Emit(OpCodes.Castclass, paramType);
//}
else // 如果是引用类型,直接转换
{
il.Emit(OpCodes.Castclass, paramType);
}
}
// 调用方法:静态方法使用 Call实例方法使用 Callvirt
if (isStatic)
{
il.Emit(OpCodes.Call, methodInfo); // 对于静态方法,使用 Call
}
else
{
il.Emit(OpCodes.Callvirt, methodInfo); // 对于实例方法,使用 Callvirt
}
//// 处理返回值如果没有返回值则返回null
if (methodInfo.ReturnType == typeof(void))
{
il.Emit(OpCodes.Ldnull);
}
else if (methodInfo.ReturnType.IsValueType)
{
il.Emit(OpCodes.Box, methodInfo.ReturnType); // 如果是值类型,将其装箱
}
// 处理返回值如果没有返回值则返回null
il.Emit(OpCodes.Ret); // 返回
if (IsTask)
{
if (IsTaskGenerics)
{
@delegate = dynamicMethod.CreateDelegate(typeof(Func<object, object[], Task<object>>));
}
else
{
@delegate = dynamicMethod.CreateDelegate(typeof(Func<object, object[], Task>));
}
}
else
{
@delegate = dynamicMethod.CreateDelegate(typeof(Func<object, object[], object>));
}
return new EmitMethodInfo
{
DeclaringType = methodInfo.DeclaringType,
IsTask = IsTask,
IsStatic = isStatic
};
}
}
}