mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-03 00:00:49 +08:00
修改了http服务器无法正确处理post请求入参;添加了modbus tcp客户端支持。
This commit is contained in:
@@ -39,7 +39,7 @@ namespace Serein.Script.Node
|
||||
public CollectionIndexNode Collection { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 索引来源
|
||||
/// 赋值值来源
|
||||
/// </summary>
|
||||
public ASTNode Value { get; }
|
||||
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
<None Remove="Tool\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Node\ExpressionNode.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Library\Serein.Library.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Serein.Library;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Serein.Library;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Script.Node;
|
||||
using Serein.Script.Node.FlowControl;
|
||||
@@ -22,7 +23,7 @@ namespace Serein.Script
|
||||
/// <summary>
|
||||
/// 类型分析
|
||||
/// </summary>
|
||||
public SereinScriptTypeAnalysis TypeAnalysis { get; set; } = new SereinScriptTypeAnalysis();
|
||||
public SereinScriptTypeAnalysis TypeAnalysis { get; } = new SereinScriptTypeAnalysis();
|
||||
|
||||
|
||||
|
||||
@@ -34,7 +35,7 @@ namespace Serein.Script
|
||||
SereinScriptParser parser = new SereinScriptParser();
|
||||
SereinScriptTypeAnalysis analysis = new SereinScriptTypeAnalysis();
|
||||
var programNode = parser.Parse(script);
|
||||
analysis.NodeSymbolInfos.Clear(); // 清空符号表
|
||||
analysis.Reset();
|
||||
if (argTypes is not null) analysis.LoadSymbol(argTypes); // 提前加载脚本节点定义的符号
|
||||
analysis.Analysis(programNode); // 分析节点类型
|
||||
SereinScriptInterpreter Interpreter = new SereinScriptInterpreter(analysis.NodeSymbolInfos);
|
||||
@@ -61,6 +62,14 @@ namespace Serein.Script
|
||||
return returnType; // 脚本返回类型
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 执行脚本
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
public async Task<object?> InterpreterAsync(IScriptInvokeContext context)
|
||||
{
|
||||
if(programNode is null)
|
||||
@@ -73,6 +82,35 @@ namespace Serein.Script
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 转换为c#代码
|
||||
/// </summary>
|
||||
/// <param name="script">脚本</param>
|
||||
/// <param name="argTypes">挂载的变量</param>
|
||||
/// <returns></returns>
|
||||
public string ConvertCSharpCode(string mehtodName, Dictionary<string, Type>? argTypes = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(mehtodName)) return string.Empty;
|
||||
if (programNode is null) return string.Empty;
|
||||
SereinScriptToCsharpScript tool = new SereinScriptToCsharpScript(TypeAnalysis);
|
||||
return tool.CompileToCSharp(mehtodName, programNode, argTypes);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 编译为 IL 代码
|
||||
/// </summary>
|
||||
/// <param name="script">脚本</param>
|
||||
/// <param name="argTypes">挂载的变量</param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("因为暂未想到如何支持异步方法,所以暂时废弃生成", true)]
|
||||
private Delegate CompilerIL(string dynamicMethodName, ProgramNode programNode, Dictionary<string, Type>? argTypes = null)
|
||||
{
|
||||
SereinScriptILCompiler compiler = new SereinScriptILCompiler(TypeAnalysis.NodeSymbolInfos);
|
||||
var @delegate = compiler.Compiler(dynamicMethodName, programNode, argTypes); // 编译脚本
|
||||
return @delegate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -96,10 +134,10 @@ namespace Serein.Script
|
||||
/// <summary>
|
||||
/// 挂载的函数调用的对象(用于解决函数需要实例才能调用的场景)
|
||||
/// </summary>
|
||||
public static Dictionary<string, Func<object>> DelegateInstances = new Dictionary<string, Func<object>>();
|
||||
// public static Dictionary<string, Func<object>> DelegateInstances = new Dictionary<string, Func<object>>();
|
||||
|
||||
/// <summary>
|
||||
/// 挂载静态函数
|
||||
/// 挂载函数
|
||||
/// </summary>
|
||||
/// <param name="functionName"></param>
|
||||
/// <param name="methodInfo"></param>
|
||||
@@ -115,7 +153,7 @@ namespace Serein.Script
|
||||
/// </summary>
|
||||
/// <param name="functionName">函数名称</param>
|
||||
/// <param name="methodInfo">方法信息</param>
|
||||
public static void AddFunction(string functionName, MethodInfo methodInfo, Func<object>? callObj = null)
|
||||
/*public static void AddFunction(string functionName, MethodInfo methodInfo, Func<object>? callObj = null)
|
||||
{
|
||||
if (!methodInfo.IsStatic && callObj is null)
|
||||
{
|
||||
@@ -132,7 +170,7 @@ namespace Serein.Script
|
||||
{
|
||||
FunctionDelegates[functionName] = new DelegateDetails(methodInfo);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
/// <summary>
|
||||
/// 挂载类型
|
||||
|
||||
38
Serein.Script/SereinScriptExtension.cs
Normal file
38
Serein.Script/SereinScriptExtension.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Script
|
||||
{
|
||||
internal static class SereinScriptExtension
|
||||
{ /// <summary>
|
||||
/// 添加代码
|
||||
/// </summary>
|
||||
/// <param name="sb">字符串构建器</param>
|
||||
/// <param name="retractCount">缩进次数(4个空格)</param>
|
||||
/// <param name="code">要添加的代码</param>
|
||||
/// <returns>字符串构建器本身</returns>
|
||||
public static StringBuilder AppendCode(this StringBuilder sb,
|
||||
int retractCount = 0,
|
||||
string code = null,
|
||||
bool isWrapping = true)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(code))
|
||||
{
|
||||
string retract = new string(' ', retractCount * 4);
|
||||
sb.Append(retract);
|
||||
if (isWrapping)
|
||||
{
|
||||
sb.AppendLine(code);
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(code);
|
||||
}
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
}
|
||||
}
|
||||
1215
Serein.Script/SereinScriptILCompiler.cs
Normal file
1215
Serein.Script/SereinScriptILCompiler.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -42,13 +42,6 @@ namespace Serein.Script
|
||||
return result; // 返回最后一个节点的结果
|
||||
}
|
||||
|
||||
/*
|
||||
async Task<object?> InterpreterAsync(IScriptInvokeContext context, ProgramNode node)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return await InterpreterAsync(context, node);
|
||||
*/
|
||||
private async Task<object?> InterpretAsync(IScriptInvokeContext context, ASTNode node)
|
||||
{
|
||||
switch (node)
|
||||
@@ -243,8 +236,8 @@ namespace Serein.Script
|
||||
return await InterpreterObjectInstantiationNodeAsync(context, objectInstantiationNode);
|
||||
case CtorAssignmentNode ctorAssignmentNode:
|
||||
return default;
|
||||
case ExpressionNode expressionNode: // 类型表达式(链式调用)
|
||||
return await InterpretAsync(context, expressionNode.Value); // 直接计算表达式的值
|
||||
/*case ExpressionNode expressionNode: // 类型表达式(链式调用)
|
||||
return await InterpretAsync(context, expressionNode.Value); // 直接计算表达式的值*/
|
||||
case MemberAccessNode memberAccessNode: // 对象成员访问
|
||||
async Task<object?> InterpreterMemberAccessNodeAsync(IScriptInvokeContext context, MemberAccessNode memberAccessNode)
|
||||
{
|
||||
@@ -319,7 +312,7 @@ namespace Serein.Script
|
||||
if (!SereinScript.FunctionDelegates.TryGetValue(funcName, out DelegateDetails? function))
|
||||
throw new SereinSciptException(functionCallNode, $"没有挂载方法\"{functionCallNode.FunctionName}\"");
|
||||
|
||||
if (!function.EmitMethodInfo.IsStatic)
|
||||
/* if (!function.EmitMethodInfo.IsStatic)
|
||||
{
|
||||
if (!SereinScript.DelegateInstances.TryGetValue(funcName, out var action))
|
||||
{
|
||||
@@ -331,7 +324,7 @@ namespace Serein.Script
|
||||
{
|
||||
throw new SereinSciptException(functionCallNode, $"函数 {funcName} 尝试获取实例时返回了 null ");
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
var result = await function.InvokeAsync(instance, arguments);
|
||||
return result;
|
||||
|
||||
464
Serein.Script/SereinScriptToCsharpScript.cs
Normal file
464
Serein.Script/SereinScriptToCsharpScript.cs
Normal file
@@ -0,0 +1,464 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Serein.Library;
|
||||
using Serein.Script.Node;
|
||||
using Serein.Script.Node.FlowControl;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net.Security;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Serein.Script
|
||||
{
|
||||
/// <summary>
|
||||
/// 将 Serein 脚本转换为 C# 脚本的类
|
||||
/// </summary>
|
||||
internal class SereinScriptToCsharpScript
|
||||
{
|
||||
/// <summary>
|
||||
/// 符号表
|
||||
/// </summary>
|
||||
private readonly Dictionary<ASTNode, Type> _symbolInfos;
|
||||
|
||||
/// <summary>
|
||||
/// 记录方法节点是否需要异步调用
|
||||
/// </summary>
|
||||
private readonly Dictionary<ASTNode, bool> _asyncMethods;
|
||||
|
||||
/// <summary>
|
||||
/// 临时变量表
|
||||
/// </summary>
|
||||
private readonly Dictionary<string, Type> _local = [];
|
||||
|
||||
private bool _isTaskMain = false;
|
||||
|
||||
public SereinScriptToCsharpScript(SereinScriptTypeAnalysis analysis)
|
||||
{
|
||||
_symbolInfos = analysis.NodeSymbolInfos;
|
||||
_asyncMethods = analysis.AsyncMethods;
|
||||
_isTaskMain = _asyncMethods.Any(kvp => kvp.Value);
|
||||
}
|
||||
|
||||
private readonly StringBuilder _codeBuilder = new StringBuilder();
|
||||
private int _indentLevel = 0;
|
||||
|
||||
private void AppendLine(string code)
|
||||
{
|
||||
_codeBuilder.AppendLine(new string(' ', _indentLevel * 4) + code);
|
||||
}
|
||||
|
||||
private void Append(string code)
|
||||
{
|
||||
_codeBuilder.Append(code);
|
||||
}
|
||||
|
||||
private void Indent() => _indentLevel++;
|
||||
private void Unindent() => _indentLevel--;
|
||||
|
||||
private List<Action<StringBuilder>> _classDefinitions = new List<Action<StringBuilder>>();
|
||||
|
||||
public string CompileToCSharp(string mehtodName, ProgramNode programNode, Dictionary<string, Type>? param)
|
||||
{
|
||||
_codeBuilder.Clear();
|
||||
var sb = _codeBuilder;
|
||||
var methodResultType = _symbolInfos[programNode];
|
||||
if(methodResultType == typeof(void))
|
||||
{
|
||||
methodResultType = typeof(object);
|
||||
}
|
||||
var taskFullName = typeof(Task).FullName;
|
||||
var returnContent = _isTaskMain ? $"global::{taskFullName}<global::{methodResultType.FullName}>" : $"global::{methodResultType.FullName}";
|
||||
|
||||
AppendLine("public class SereinScriptToCsharp");
|
||||
AppendLine( "{");
|
||||
Indent();
|
||||
if(param is null || param.Count == 0)
|
||||
{
|
||||
AppendLine($"public static {returnContent} {mehtodName}()");
|
||||
}
|
||||
else
|
||||
{
|
||||
AppendLine($"public static {returnContent} {mehtodName}({GetMethodParamster(param)})");
|
||||
}
|
||||
AppendLine( "{");
|
||||
Indent();
|
||||
foreach (var stmt in programNode.Statements)
|
||||
{
|
||||
ConvertCode(stmt); // 递归遍历
|
||||
Append(";");
|
||||
}
|
||||
if(!_symbolInfos.Keys.Any(node => node is ReturnNode))
|
||||
{
|
||||
AppendLine("return null;");
|
||||
}
|
||||
Unindent();
|
||||
AppendLine("}");
|
||||
Unindent();
|
||||
AppendLine("}");
|
||||
|
||||
foreach (var cd in _classDefinitions)
|
||||
{
|
||||
cd.Invoke(sb);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private string GetMethodParamster(Dictionary<string, Type> param)
|
||||
{
|
||||
var values = param.Select(kvp =>
|
||||
{
|
||||
_local[kvp.Key] = kvp.Value;
|
||||
return $"global::{kvp.Value.FullName} {kvp.Key}";
|
||||
});
|
||||
return string.Join(',', values);
|
||||
}
|
||||
|
||||
private void ConvertCode( ASTNode node)
|
||||
{
|
||||
switch (node)
|
||||
{
|
||||
case ProgramNode programNode: // 程序开始节点
|
||||
break;
|
||||
case ReturnNode returnNode: // 程序退出节点
|
||||
void ConvertCodeOfReturnNode(ReturnNode returnNode)
|
||||
{
|
||||
if (returnNode.Value is not null)
|
||||
{
|
||||
Append($"return ");
|
||||
ConvertCode(returnNode.Value);
|
||||
Append(";");
|
||||
AppendLine(string.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
AppendLine("return defult;");
|
||||
}
|
||||
}
|
||||
ConvertCodeOfReturnNode(returnNode);
|
||||
break;
|
||||
#region 字面量解析
|
||||
case NullNode nullNode: // null
|
||||
Append("null");
|
||||
break;
|
||||
case CharNode charNode: // char字面量
|
||||
Append($"'{charNode.Value}'");
|
||||
break;
|
||||
case StringNode stringNode: // 字符串字面量
|
||||
Append($"\"{stringNode.Value}\"");
|
||||
break;
|
||||
case BooleanNode booleanNode: // 布尔值字面量
|
||||
Append($"{(booleanNode.Value ? "true" : "false")}");
|
||||
break;
|
||||
case NumberIntNode numberIntNode: // int整型数值字面量
|
||||
Append($"{numberIntNode.Value}");
|
||||
break;
|
||||
case NumberLongNode numberLongNode: // long整型数值字面量
|
||||
Append($"{numberLongNode.Value}");
|
||||
break;
|
||||
case NumberFloatNode numberFloatNode: // float浮点数值字面量
|
||||
Append($"{numberFloatNode.Value}f");
|
||||
break;
|
||||
case NumberDoubleNode numberDoubleNode: // double浮点数值字面量
|
||||
Append($"{numberDoubleNode.Value}d");
|
||||
break;
|
||||
#endregion
|
||||
case IdentifierNode identifierNode: // 变量定义
|
||||
void ConvertCodeOfIdentifierNode(IdentifierNode identifierNode)
|
||||
{
|
||||
var varName = identifierNode.Name;
|
||||
|
||||
if(_local.TryGetValue(varName, out var type))
|
||||
{
|
||||
// 定义过,需要使用变量
|
||||
Append(varName);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_symbolInfos.TryGetValue(identifierNode, out type))
|
||||
{
|
||||
// 不存在,定义变量
|
||||
Append($"global::{type.FullName} {varName}");
|
||||
_local[varName] = type;
|
||||
//Append(varName);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"加载符号表时,无法匹配 IdentifierNode 节点的类型。 name : {varName}");
|
||||
}
|
||||
}
|
||||
}
|
||||
ConvertCodeOfIdentifierNode(identifierNode);
|
||||
break;
|
||||
case IfNode ifNode: // if语句结构
|
||||
void ConvertCodeOfIfNode(IfNode ifNOde)
|
||||
{
|
||||
AppendLine("");
|
||||
Append($"if(");
|
||||
ConvertCode(ifNOde.Condition); // 解析条件
|
||||
Append($" == true)");
|
||||
AppendLine("{");
|
||||
Indent();
|
||||
foreach(var item in ifNOde.TrueBranch)
|
||||
{
|
||||
ConvertCode(item);
|
||||
//Append(";");
|
||||
AppendLine(string.Empty);
|
||||
}
|
||||
Unindent();
|
||||
AppendLine("}");
|
||||
AppendLine("else");
|
||||
AppendLine("{");
|
||||
Indent();
|
||||
foreach (var item in ifNOde.TrueBranch)
|
||||
{
|
||||
ConvertCode(item);
|
||||
//Append(";");
|
||||
AppendLine(string.Empty);
|
||||
}
|
||||
Unindent();
|
||||
AppendLine("}");
|
||||
}
|
||||
ConvertCodeOfIfNode(ifNode);
|
||||
break;
|
||||
case WhileNode whileNode: // while语句结构
|
||||
void ConvertCodeOfWhileNode(WhileNode whileNode)
|
||||
{
|
||||
AppendLine("");
|
||||
Append($"while(");
|
||||
ConvertCode(whileNode.Condition); // 解析条件
|
||||
Append($" == {true})");
|
||||
AppendLine("{");
|
||||
Indent();
|
||||
foreach (var item in whileNode.Body)
|
||||
{
|
||||
ConvertCode(item);
|
||||
Append(";");
|
||||
AppendLine(string.Empty);
|
||||
}
|
||||
Unindent();
|
||||
AppendLine("}");
|
||||
}
|
||||
ConvertCodeOfWhileNode(whileNode);
|
||||
break;
|
||||
case AssignmentNode assignmentNode: // 变量赋值语句
|
||||
void ConvertCodeOfAssignmentNode(AssignmentNode assignmentNode)
|
||||
{
|
||||
ConvertCode(assignmentNode.Target);
|
||||
Append(" = ");
|
||||
if (assignmentNode.Value is null)
|
||||
{
|
||||
Append("null");
|
||||
}
|
||||
else
|
||||
{
|
||||
ConvertCode(assignmentNode.Value);
|
||||
}
|
||||
Append(";");
|
||||
AppendLine(string.Empty);
|
||||
}
|
||||
ConvertCodeOfAssignmentNode(assignmentNode);
|
||||
break;
|
||||
case BinaryOperationNode binaryOperationNode: // 二元运算操作
|
||||
void ConvertCodeOfBinaryOperationNode(BinaryOperationNode binaryOperationNode)
|
||||
{
|
||||
Append("(");
|
||||
ConvertCode(binaryOperationNode.Left); // 左操作数
|
||||
Append(binaryOperationNode.Operator); // 操作符
|
||||
ConvertCode(binaryOperationNode.Right); // 左操作数
|
||||
Append(")");
|
||||
}
|
||||
ConvertCodeOfBinaryOperationNode(binaryOperationNode);
|
||||
break;
|
||||
case CollectionAssignmentNode collectionAssignmentNode:
|
||||
void ConvertCodeOfCollectionAssignmentNode(CollectionAssignmentNode collectionAssignmentNode)
|
||||
{
|
||||
ConvertCode(collectionAssignmentNode.Collection);
|
||||
Append(" = ");
|
||||
ConvertCode(collectionAssignmentNode.Value);
|
||||
Append(";");
|
||||
AppendLine(string.Empty);
|
||||
}
|
||||
ConvertCodeOfCollectionAssignmentNode(collectionAssignmentNode);
|
||||
break;
|
||||
case CollectionIndexNode collectionIndexNode: // 集合类型操作
|
||||
void ConvertCodeOfCollectionIndexNode(CollectionIndexNode collectionIndexNode)
|
||||
{
|
||||
ConvertCode(collectionIndexNode.Collection);
|
||||
Append("[");
|
||||
ConvertCode(collectionIndexNode.Index);
|
||||
Append("]");
|
||||
}
|
||||
ConvertCodeOfCollectionIndexNode(collectionIndexNode);
|
||||
break;
|
||||
case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义
|
||||
void ConvertCodeOfClassTypeDefinitionNode(ClassTypeDefinitionNode classTypeDefinitionNode)
|
||||
{
|
||||
_classDefinitions.Add((sb) =>
|
||||
{
|
||||
var type = _symbolInfos[classTypeDefinitionNode.ClassType];
|
||||
AppendLine($"public class {type.FullName}");
|
||||
AppendLine("{");
|
||||
Indent();
|
||||
foreach (var property in classTypeDefinitionNode.Propertys)
|
||||
{
|
||||
var propertyName = property.Key;
|
||||
var propertyType = _symbolInfos[property.Value];
|
||||
AppendLine($"public global::{propertyType.FullName} {propertyName} {{ get; set; }}");
|
||||
}
|
||||
Unindent();
|
||||
AppendLine("}");
|
||||
});
|
||||
}
|
||||
ConvertCodeOfClassTypeDefinitionNode(classTypeDefinitionNode);
|
||||
break;
|
||||
case TypeNode typeNode: // 类型
|
||||
break;
|
||||
case ObjectInstantiationNode objectInstantiationNode: // 类型实例化
|
||||
void ConvertCodeOfObjectInstantiationNode(ObjectInstantiationNode objectInstantiationNode)
|
||||
{
|
||||
var type = _symbolInfos[objectInstantiationNode.Type];
|
||||
Append($"new global::{type}");
|
||||
if (objectInstantiationNode.Arguments.Count > 0)
|
||||
{
|
||||
Append("(");
|
||||
for (int i = 0; i < objectInstantiationNode.Arguments.Count; i++)
|
||||
{
|
||||
ConvertCode(objectInstantiationNode.Arguments[i]);
|
||||
if (i < objectInstantiationNode.Arguments.Count - 1)
|
||||
{
|
||||
Append(", ");
|
||||
}
|
||||
}
|
||||
Append(")");
|
||||
}
|
||||
else
|
||||
{
|
||||
Append("()");
|
||||
}
|
||||
if (objectInstantiationNode.CtorAssignments.Count > 0)
|
||||
{
|
||||
AppendLine("{");
|
||||
Indent();
|
||||
foreach (var assignment in objectInstantiationNode.CtorAssignments)
|
||||
{
|
||||
ConvertCode(assignment);
|
||||
}
|
||||
Unindent();
|
||||
AppendLine("}");
|
||||
}
|
||||
}
|
||||
ConvertCodeOfObjectInstantiationNode(objectInstantiationNode);
|
||||
break;
|
||||
case CtorAssignmentNode ctorAssignmentNode: // 构造器赋值
|
||||
void ConvertCodeOfCtorAssignmentNode(CtorAssignmentNode ctorAssignmentNode)
|
||||
{
|
||||
var propertyName = ctorAssignmentNode.MemberName;
|
||||
var value = ctorAssignmentNode.Value;
|
||||
Append($"{propertyName} = ");
|
||||
ConvertCode(value);
|
||||
AppendLine(",");
|
||||
}
|
||||
ConvertCodeOfCtorAssignmentNode(ctorAssignmentNode);
|
||||
break;
|
||||
case MemberAccessNode memberAccessNode: // 对象成员访问
|
||||
void ConvertCodeOfMemberAccessNode(MemberAccessNode memberAccessNode)
|
||||
{
|
||||
ConvertCode(memberAccessNode.Object);
|
||||
Append($".{memberAccessNode.MemberName}");
|
||||
}
|
||||
ConvertCodeOfMemberAccessNode(memberAccessNode);
|
||||
break;
|
||||
case MemberAssignmentNode memberAssignmentNode: // 对象成员赋值
|
||||
void ConvertCodeOfMemberAssignmentNode(MemberAssignmentNode memberAssignmentNode)
|
||||
{
|
||||
ConvertCode(memberAssignmentNode.Object);
|
||||
Append($".{memberAssignmentNode.MemberName} = ");
|
||||
ConvertCode(memberAssignmentNode.Value);
|
||||
Append($";");
|
||||
AppendLine(string.Empty);
|
||||
}
|
||||
ConvertCodeOfMemberAssignmentNode(memberAssignmentNode);
|
||||
break;
|
||||
case MemberFunctionCallNode memberFunctionCallNode: // 对象方法调用
|
||||
void ConvertCodeOfMemberFunctionCallNode(MemberFunctionCallNode memberFunctionCallNode)
|
||||
{
|
||||
var isAsync = _asyncMethods.TryGetValue(memberFunctionCallNode, out var isAsyncValue) && isAsyncValue;
|
||||
if (isAsync)
|
||||
{
|
||||
Append($"(await ");
|
||||
}
|
||||
|
||||
ConvertCode(memberFunctionCallNode.Object);
|
||||
Append($".{memberFunctionCallNode.FunctionName}(");
|
||||
for (int i = 0; i < memberFunctionCallNode.Arguments.Count; i++)
|
||||
{
|
||||
ASTNode? argNode = memberFunctionCallNode.Arguments[i];
|
||||
ConvertCode(argNode);
|
||||
if (i < memberFunctionCallNode.Arguments.Count - 1)
|
||||
{
|
||||
Append(", ");
|
||||
}
|
||||
}
|
||||
Append($")");
|
||||
if (isAsync)
|
||||
{
|
||||
Append($")");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
ConvertCodeOfMemberFunctionCallNode(memberFunctionCallNode);
|
||||
break;
|
||||
case FunctionCallNode functionCallNode: // 外部挂载的函数调用
|
||||
void ConvertCodeOfFunctionCallNode(FunctionCallNode functionCallNode)
|
||||
{
|
||||
var isAsync = _asyncMethods.TryGetValue(functionCallNode, out var isAsyncValue) && isAsyncValue;
|
||||
if (isAsync)
|
||||
{
|
||||
Append($"(await ");
|
||||
}
|
||||
var funcName = functionCallNode.FunctionName switch
|
||||
{
|
||||
"int" => "@int" ,
|
||||
"bool" => "@bool" ,
|
||||
"double" => "@double" ,
|
||||
"long" => "@long" ,
|
||||
"decimal" => "@decimal" ,
|
||||
"float" => "@float" ,
|
||||
"byte" => "@byte" ,
|
||||
|
||||
_ => functionCallNode.FunctionName,
|
||||
};
|
||||
Append($"global::Serein.Library.ScriptBaseFunc.{funcName}(");
|
||||
for (int i = 0; i < functionCallNode.Arguments.Count; i++)
|
||||
{
|
||||
ASTNode? argNode = functionCallNode.Arguments[i];
|
||||
ConvertCode(argNode);
|
||||
if (i < functionCallNode.Arguments.Count - 1)
|
||||
{
|
||||
Append(", ");
|
||||
}
|
||||
}
|
||||
Append($")");
|
||||
if (isAsync)
|
||||
{
|
||||
Append($")");
|
||||
}
|
||||
}
|
||||
ConvertCodeOfFunctionCallNode(functionCallNode);
|
||||
break;
|
||||
default: // 未定义的节点类型
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using Serein.Script.Node.FlowControl;
|
||||
using Serein.Script.Symbol;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Reactive;
|
||||
using System.Reflection;
|
||||
@@ -27,6 +28,17 @@ namespace Serein.Script
|
||||
/// </summary>
|
||||
public Dictionary<ASTNode, Type> NodeSymbolInfos { get; } = new Dictionary<ASTNode, Type>();
|
||||
|
||||
/// <summary>
|
||||
/// 记录方法节点是否需要进行异步调用
|
||||
/// </summary>
|
||||
public Dictionary<ASTNode, bool> AsyncMethods { get; } = new Dictionary<ASTNode, bool>();
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
NodeSymbolInfos.Clear(); // 清空符号表
|
||||
AsyncMethods.Clear();
|
||||
}
|
||||
|
||||
public void LoadSymbol(Dictionary<string,Type> identifierNodes)
|
||||
{
|
||||
foreach(var kvp in identifierNodes)
|
||||
@@ -74,6 +86,7 @@ namespace Serein.Script
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 类型获取
|
||||
@@ -293,7 +306,7 @@ namespace Serein.Script
|
||||
return valueType;
|
||||
}
|
||||
return AnalysisCtorAssignmentNode(ctorAssignmentNode);
|
||||
case ExpressionNode expressionNode: // 类型表达式(链式调用)
|
||||
/*case ExpressionNode expressionNode: // 类型表达式(链式调用)
|
||||
Type AnalysisObjectMemberExpressionNode(ExpressionNode expressionNode)
|
||||
{
|
||||
// 1. 对象成员获取 MemberAccessNode
|
||||
@@ -304,7 +317,7 @@ namespace Serein.Script
|
||||
NodeSymbolInfos[expressionNode] = resultType;
|
||||
return resultType;
|
||||
}
|
||||
return AnalysisObjectMemberExpressionNode(expressionNode);
|
||||
return AnalysisObjectMemberExpressionNode(expressionNode);*/
|
||||
case MemberAccessNode memberAccessNode: // 对象成员访问
|
||||
Type AnalysisMemberAccessNode(MemberAccessNode memberAccessNode)
|
||||
{
|
||||
@@ -365,9 +378,12 @@ namespace Serein.Script
|
||||
Type argType = types[index];
|
||||
NodeSymbolInfos[argNode] = argType;
|
||||
}
|
||||
var isAsync = IsGenericTask(methodInfo.ReturnType, out var taskResult);
|
||||
var methodReturnType = isAsync ? taskResult : methodInfo.ReturnType;
|
||||
AsyncMethods[memberFunctionCallNode] = isAsync;
|
||||
NodeSymbolInfos[memberFunctionCallNode.Object] = objectType;
|
||||
NodeSymbolInfos[memberFunctionCallNode] = methodInfo.ReturnType;
|
||||
return methodInfo.ReturnType;
|
||||
NodeSymbolInfos[memberFunctionCallNode] = methodReturnType;
|
||||
return methodReturnType;
|
||||
|
||||
|
||||
}
|
||||
@@ -386,8 +402,11 @@ namespace Serein.Script
|
||||
Type argType = types[index];
|
||||
NodeSymbolInfos[argNode] = argType;
|
||||
}
|
||||
NodeSymbolInfos[functionCallNode] = methodInfo.ReturnType;
|
||||
return methodInfo.ReturnType;
|
||||
var isAsync = IsGenericTask(methodInfo.ReturnType, out var taskResult);
|
||||
var methodReturnType = isAsync ? taskResult : methodInfo.ReturnType;
|
||||
AsyncMethods[functionCallNode] = isAsync;
|
||||
NodeSymbolInfos[functionCallNode] = methodReturnType;
|
||||
return methodReturnType;
|
||||
}
|
||||
return AnalysisFunctionCallNode(functionCallNode);
|
||||
default: // 未定义的节点类型
|
||||
@@ -398,7 +417,6 @@ namespace Serein.Script
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 类型分析
|
||||
/// </summary>
|
||||
@@ -472,9 +490,9 @@ namespace Serein.Script
|
||||
case ObjectInstantiationNode objectInstantiationNode: // 类型实例化
|
||||
Analysis(objectInstantiationNode);
|
||||
break;
|
||||
case ExpressionNode expressionNode: // 类型表达式(链式调用)
|
||||
/* case ExpressionNode expressionNode: // 类型表达式(链式调用)
|
||||
Analysis(expressionNode.Value);
|
||||
break;
|
||||
break;*/
|
||||
case MemberAccessNode memberAccessNode: // 对象成员访问
|
||||
Analysis(memberAccessNode);
|
||||
break;
|
||||
@@ -497,7 +515,7 @@ namespace Serein.Script
|
||||
}
|
||||
|
||||
|
||||
private void Analysis2(ASTNode node)
|
||||
private void ToILCompiler(ASTNode node)
|
||||
{
|
||||
switch (node)
|
||||
{
|
||||
@@ -541,9 +559,7 @@ namespace Serein.Script
|
||||
break;
|
||||
case ObjectInstantiationNode objectInstantiationNode: // 类型实例化
|
||||
break;
|
||||
case CtorAssignmentNode ctorAssignmentNode:
|
||||
break;
|
||||
case ExpressionNode expressionNode: // 类型表达式(链式调用)
|
||||
case CtorAssignmentNode ctorAssignmentNode: // 构造器赋值
|
||||
break;
|
||||
case MemberAccessNode memberAccessNode: // 对象成员访问
|
||||
break;
|
||||
@@ -582,8 +598,28 @@ namespace Serein.Script
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsGenericTask(Type returnType, out Type taskResult)
|
||||
{
|
||||
// 判断是否为 Task 类型或泛型 Task<T>
|
||||
if (returnType == typeof(Task))
|
||||
{
|
||||
taskResult = typeof(void);
|
||||
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>
|
||||
/// 获取某个集合类型支持的索引参数类型
|
||||
|
||||
Reference in New Issue
Block a user