mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-02 15:50:47 +08:00
1. 移除了FlipflopContext,统一流程API
2. Script项目脚本修复了 RawString 原始字符串存在的问题 3. Script使用了ValueNode统一了值类型节点,为后续扩展更多的值类型做准备 4. TypeHelper.ToTypeOfString()方法中添加了部分值类型的"Type[]”与“List<Type>”的显式定义,用于脚本在类型中定义数组成员 5. Script项目脚本默认挂载的json方法拆分为jsonObj(String)与jsonStr(Object)以支持序列化与反序列化 6. 项目保存为dnf项目文件时,将不再保存名称为”Default"并且没有节点的画布,避免重复保存时默认画布增多。
This commit is contained in:
@@ -9,14 +9,7 @@ namespace Serein.Script.Node
|
||||
/// <summary>
|
||||
/// 布尔字面量
|
||||
/// </summary>
|
||||
public class BooleanNode : ASTNode
|
||||
public class BooleanNode(bool value) : ValueNode<bool>(value)
|
||||
{
|
||||
public bool Value { get; }
|
||||
public BooleanNode(bool value) => Value = value;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Value}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,16 +6,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Script.Node
|
||||
{
|
||||
internal class CharNode : ASTNode
|
||||
internal class CharNode(char value) : ValueNode<char>(value)
|
||||
{
|
||||
public char Value { get; }
|
||||
public CharNode(string value)
|
||||
{
|
||||
Value = char.Parse(value);
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
return $"'{Value}'";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,15 +9,9 @@ namespace Serein.Script.Node
|
||||
/// <summary>
|
||||
/// 数值型节点
|
||||
/// </summary>
|
||||
public abstract class NumberNode<T> : ASTNode where T : struct, IComparable<T>
|
||||
public abstract class NumberNode<T> : ValueNode<T> where T : struct, IComparable<T>
|
||||
{
|
||||
public T Value { get; }
|
||||
public NumberNode(T value) => Value = value;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Value}";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
8
Serein.Script/Node/ValueNode/RawStringNode.cs
Normal file
8
Serein.Script/Node/ValueNode/RawStringNode.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Serein.Script.Node
|
||||
{
|
||||
public class RawStringNode(string value) : ValueNode<string>(value)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -9,11 +9,9 @@ namespace Serein.Script.Node
|
||||
/// <summary>
|
||||
/// 字符串字面量节点
|
||||
/// </summary>
|
||||
public class StringNode : ASTNode
|
||||
public class StringNode : ValueNode<string>
|
||||
{
|
||||
public string Value { get; }
|
||||
|
||||
public StringNode(string input)
|
||||
public StringNode(string input) : base()
|
||||
{
|
||||
// 使用 StringBuilder 来构建输出
|
||||
StringBuilder output = new StringBuilder(input.Length);
|
||||
@@ -59,11 +57,6 @@ namespace Serein.Script.Node
|
||||
}
|
||||
Value = output.ToString();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"\"{Value}\"";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
26
Serein.Script/Node/ValueNode/ValueNode.cs
Normal file
26
Serein.Script/Node/ValueNode/ValueNode.cs
Normal 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 class ValueNode<T> : ASTNode
|
||||
{
|
||||
public T Value { get; protected set; }
|
||||
|
||||
public ValueNode()
|
||||
{
|
||||
|
||||
}
|
||||
public ValueNode(T value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Value}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,8 @@ namespace Serein.Script
|
||||
return null; // 返回 null
|
||||
case CharNode charNode: // char字面量
|
||||
return charNode.Value; // 返回字符值
|
||||
case RawStringNode rawStringNode:
|
||||
return rawStringNode.Value; // 返回原始字符串值
|
||||
case StringNode stringNode: // 字符串字面量
|
||||
return stringNode.Value; // 返回字符串值
|
||||
case BooleanNode booleanNode: // 布尔值字面量
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
namespace Serein.Script
|
||||
using System.Data.Common;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Serein.Script
|
||||
{
|
||||
/// <summary>
|
||||
/// Serein脚本词法分析器的Token类型
|
||||
@@ -38,6 +41,10 @@
|
||||
/// </summary>
|
||||
String,
|
||||
/// <summary>
|
||||
/// 原始字符串(多行字符串)
|
||||
/// </summary>
|
||||
RawString,
|
||||
/// <summary>
|
||||
/// Char字符
|
||||
/// </summary>
|
||||
Char,
|
||||
@@ -217,7 +224,7 @@
|
||||
if (_input[_index + 1] == '"'
|
||||
&& _input[_index + 2] == '"')
|
||||
{
|
||||
var value = _input.Slice(_index, 4).ToString();
|
||||
//var value = _input.Slice(_index, 4).ToString();
|
||||
|
||||
// 原始字符串
|
||||
return ReadRawString();
|
||||
@@ -450,27 +457,38 @@
|
||||
|
||||
private Token ReadRawString()
|
||||
{
|
||||
// skip opening triple quotes
|
||||
_index += 3;
|
||||
|
||||
var start = _index;
|
||||
while (_index + 2 < _input.Length)
|
||||
int startLine = _row;
|
||||
_index += 3; // 跳过开头 """
|
||||
int index = _index;
|
||||
var contentStart = index;
|
||||
while (index + 2 < _input.Length)
|
||||
{
|
||||
if (_input[_index] == '"' && _input[_index + 1] == '"' && _input[_index + 2] == '"')
|
||||
char current = _input[index];
|
||||
|
||||
// 行号处理
|
||||
if (current == '\n')
|
||||
{
|
||||
var value = _input.Slice(start, _index - start).ToString();
|
||||
_index += 3; // skip closing """
|
||||
return CreateToken(TokenType.String, value);
|
||||
_row++;
|
||||
}
|
||||
|
||||
// 检查是否是结束符 """
|
||||
if (_input[index] != '"' || _input[index + 1] != '"' || _input[index + 2] != '"')
|
||||
{
|
||||
index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
var value = _input.Slice(contentStart, index - contentStart).ToString();
|
||||
_index += 3;
|
||||
// 构建带行号信息的 Token(假设 Token 有 StartLine 属性)
|
||||
return CreateToken(TokenType.RawString, value);
|
||||
}
|
||||
|
||||
_index++;
|
||||
}
|
||||
|
||||
throw new Exception("Unterminated raw string literal");
|
||||
|
||||
throw new Exception($"Unterminated raw string literal starting at line {startLine}");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 读取硬编码的文本
|
||||
/// </summary>
|
||||
|
||||
@@ -112,9 +112,9 @@ namespace Serein.Script
|
||||
isAssignment = true;
|
||||
break;
|
||||
}
|
||||
if(peekCount > 19999)
|
||||
if(peekCount > 3999)
|
||||
{
|
||||
throw new Exception("解析异常,peek次数过多,请减少脚本代码");
|
||||
throw new Exception("解析异常,peek次数过多,可能是解析器出了bug");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
@@ -122,16 +122,19 @@ namespace Serein.Script
|
||||
#region 生成赋值语句/一般语句的ASTNode
|
||||
if (isAssignment)
|
||||
{
|
||||
|
||||
// 以赋值语句的形式进行处理
|
||||
var assignmentNode = ParseAssignmentNode(); // 解析复制表达式
|
||||
NextToken();// 消耗 ";"
|
||||
//if(_currentToken.Type == TokenType.Semicolon)
|
||||
NextToken();// 消耗 ";"
|
||||
return assignmentNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 以一般语句的形式进行处理,可当作表达式进行解析
|
||||
var targetNode = ParserExpression();
|
||||
NextToken();// 消耗 ";"
|
||||
var targetNode = ParserExpression();
|
||||
//if (_currentToken.Type == TokenType.Semicolon)
|
||||
NextToken();// 消耗 ";"
|
||||
return targetNode;
|
||||
}
|
||||
#endregion
|
||||
@@ -308,6 +311,7 @@ namespace Serein.Script
|
||||
}
|
||||
else
|
||||
{
|
||||
var c = _currentToken;
|
||||
// 反转赋值。
|
||||
NextToken(); // 消耗 "=" 并获取赋值语句的右值表达式。
|
||||
ASTNode valueNode = ParserExpression();
|
||||
@@ -515,6 +519,13 @@ namespace Serein.Script
|
||||
fieldTypeName = $"{fieldTypeName}.{_currentToken.Value}"; // 向后扩充
|
||||
continue;
|
||||
}
|
||||
else if (peekToken.Type == TokenType.SquareBracketsLeft)
|
||||
{
|
||||
NextToken(); // 消耗数组类型定义的 "["
|
||||
NextToken(); // 消耗数组类型定义的 "]"
|
||||
fieldTypeName += "[]";
|
||||
continue;
|
||||
}
|
||||
else if (peekToken.Type == TokenType.Identifier)
|
||||
{
|
||||
// 尝试解析变量名称
|
||||
@@ -677,7 +688,7 @@ namespace Serein.Script
|
||||
}
|
||||
else if (_currentToken.Type == TokenType.BraceRight)
|
||||
{
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1009,6 +1020,7 @@ namespace Serein.Script
|
||||
if(peekToken.Type == TokenType.ParenthesisRight // 可能解析完了方法参数
|
||||
|| peekToken.Type == TokenType.Comma // 可能解析完了方法参数
|
||||
|| peekToken.Type == TokenType.Operator // 可能解析完了方法参数
|
||||
|| peekToken.Type == TokenType.BraceRight // 可能解析完了方法参数
|
||||
|| peekToken.Type == TokenType.ParenthesisRight) // 可能解析完了下标索引
|
||||
{
|
||||
return source;
|
||||
@@ -1065,6 +1077,13 @@ namespace Serein.Script
|
||||
NextToken(); // 消耗布尔量
|
||||
return new BooleanNode(value).SetTokenInfo(factorToken);
|
||||
}
|
||||
else if (_currentToken.Type == TokenType.RawString)
|
||||
{
|
||||
var value = _currentToken.Value;
|
||||
NextToken(); // 消耗字符串
|
||||
var node = new RawStringNode(value).SetTokenInfo(factorToken);
|
||||
return node;
|
||||
}
|
||||
else if (_currentToken.Type == TokenType.String)
|
||||
{
|
||||
var value = _currentToken.Value;
|
||||
@@ -1076,7 +1095,8 @@ namespace Serein.Script
|
||||
{
|
||||
var value = _currentToken.Value;
|
||||
NextToken(); ; // 消耗Char
|
||||
return new CharNode(value).SetTokenInfo(factorToken);
|
||||
var @char = char.Parse(value);
|
||||
return new CharNode(@char).SetTokenInfo(factorToken);
|
||||
}
|
||||
else if (_currentToken.Type == TokenType.InterpolatedString)
|
||||
{
|
||||
@@ -1186,4 +1206,6 @@ namespace Serein.Script
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@ namespace Serein.Script
|
||||
});
|
||||
return string.Join(',', values);
|
||||
}
|
||||
|
||||
|
||||
private void ConvertCode(ASTNode node)
|
||||
{
|
||||
switch (node)
|
||||
@@ -198,6 +198,12 @@ namespace Serein.Script
|
||||
case CharNode charNode: // char字面量
|
||||
Append($"'{charNode.Value}'");
|
||||
break;
|
||||
case RawStringNode rawStringNode: // 原始字符串
|
||||
AppendLine("");
|
||||
Append("\"\"\"");
|
||||
Append(rawStringNode.Value);
|
||||
Append("\"\"\"");
|
||||
break;
|
||||
case StringNode stringNode: // 字符串字面量
|
||||
Append($"\"{stringNode.Value}\"");
|
||||
break;
|
||||
@@ -502,9 +508,9 @@ namespace Serein.Script
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -128,6 +128,9 @@ namespace Serein.Script
|
||||
case CharNode charNode: // char字面量
|
||||
NodeSymbolInfos[charNode] = typeof(char);
|
||||
return typeof(char);
|
||||
case RawStringNode rawStringNode: // 原始字符串字面量(多行字符串)
|
||||
NodeSymbolInfos[rawStringNode] = typeof(string);
|
||||
return typeof(string);
|
||||
case StringNode stringNode: // 字符串字面量
|
||||
NodeSymbolInfos[stringNode] = typeof(string);
|
||||
return typeof(string);
|
||||
@@ -507,6 +510,7 @@ namespace Serein.Script
|
||||
break;
|
||||
case NullNode nullNode: // null
|
||||
case CharNode charNode: // char字面量
|
||||
case RawStringNode rawStringNode:
|
||||
case StringNode stringNode: // 字符串字面量
|
||||
case BooleanNode booleanNode: // 布尔值字面量
|
||||
case NumberIntNode numberIntNode: // int整型数值字面量
|
||||
@@ -558,6 +562,20 @@ namespace Serein.Script
|
||||
}
|
||||
AnalysisCollectionIndexNode(collectionIndexNode);
|
||||
break;
|
||||
case CollectionAssignmentNode collectionAssignmentNode: // 集合赋值操作
|
||||
void AnalysisCollectionAssignmentNode(CollectionAssignmentNode collectionAssignmentNode)
|
||||
{
|
||||
Analysis(collectionAssignmentNode);
|
||||
}
|
||||
AnalysisCollectionAssignmentNode(collectionAssignmentNode);
|
||||
break;
|
||||
case ArrayDefintionNode arrayDefintionNode:
|
||||
void AnalysisArrayDefintionNode(ArrayDefintionNode arrayDefintionNode)
|
||||
{
|
||||
Analysis(arrayDefintionNode);
|
||||
}
|
||||
AnalysisArrayDefintionNode(arrayDefintionNode);
|
||||
break;
|
||||
case ClassTypeDefinitionNode classTypeDefinitionNode: // 类型定义
|
||||
Analysis(classTypeDefinitionNode);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user