Compare commits

..

32 Commits

Author SHA1 Message Date
c4be6dba73 更新 README.md 2025-12-18 16:22:56 +08:00
249a2f9ce3 内置更加友好的类型打印 2025-12-15 11:38:49 +08:00
0a7f6eb362 更新异步step 2025-12-11 18:03:28 +08:00
e4b7dc0f55 新增重新运行的函数 2025-12-09 11:17:31 +08:00
39aab608a6 一个奇怪的修改 2025-12-04 15:38:18 +08:00
02906f836d 1.删除表达式预编译(类型不稳定)2.修复空脚本缓存读取的错误 2025-12-03 14:36:36 +08:00
f9446fb0bb Merge branch 'main' of http://www.liubai.site:3000/ninemine/RScript 2025-12-03 09:42:31 +08:00
aca8c86e97 删除从unity出现的意外修改内容 2025-12-03 09:41:48 +08:00
cdf04acecf 修复一些错误 2025-11-28 17:34:05 +08:00
1ddbeb64c2 Merge branch 'main' of http://www.liubai.site:3000/ninemine/RScript 2025-11-28 15:24:25 +08:00
90277406e8 修复goto跳转时缓存分支缺少设置跳转点的错误 2025-11-28 15:24:05 +08:00
88b0edfe6a 修复了一些bug 2025-11-26 17:58:30 +08:00
2f24d94db2 新增Enum支持 2025-11-25 17:03:43 +08:00
5b235a7f26 提升类型命名的完整度 2025-11-25 11:58:31 +08:00
29dd4f5d96 新增UndefinedIdentifiersAsStrings选项并完善变量控制器 2025-10-27 10:50:36 +08:00
971baf8c9e 新增默认脚本内容 2025-10-27 00:29:32 +08:00
104a80e527 新增预定义输出(未作验证的一次保存) 2025-10-25 21:45:31 +08:00
b7ccc387fc Save 2025-10-25 16:08:12 +08:00
4860aa251e 开始内置辅助解释 2025-10-21 15:31:28 +08:00
7eb53fc3c5 新增跳转缓存 2025-10-21 10:26:08 +08:00
58f3d1067c 修复了注释相关的分段错误 2025-10-18 17:26:07 +08:00
7b48066aaf 优化跳转 2025-10-17 16:42:52 +08:00
dde9e6b82d 新增了二进制序列化器 2025-10-17 16:24:15 +08:00
d3e21cad15 正在新增编译缓存功能,用于加速与加密 2025-10-17 15:46:44 +08:00
52e8e85542 1.新增context内置变量2.修复一些问题 2025-10-16 20:15:35 +08:00
97a6e4d76b 修复NamedSpaceRunner的遗漏 2025-10-16 17:23:37 +08:00
15bdb6f8db 解离出Runner 2025-10-16 15:20:53 +08:00
e2ab2a1077 允许变量声明时赋值 2025-10-16 11:58:05 +08:00
3866cdd525 加入自动类型转换 2025-10-16 10:24:59 +08:00
70051b46a5 namespace已经可以使用 2025-10-15 23:47:51 +08:00
35800776b9 构建命名空间规则 2025-10-15 21:18:14 +08:00
b8a87bae4c 尝试新增命名空间的命名, 用于具有名称的块或是函数 2025-10-15 16:50:10 +08:00
21 changed files with 1905 additions and 347 deletions

View File

@@ -0,0 +1,50 @@
using Convention.RScript.Parser;
using System.Collections;
using System.Diagnostics.CodeAnalysis;
namespace Convention.RScript.Runner
{
public class BackpointRunner : JumpRuntimePointerRunner
{
public override void Compile(ExpressionParser parser, RScriptSentence sentence, RScriptContext context)
{
}
[return: MaybeNull]
public override object Run(ExpressionParser parser, RScriptSentence sentence, RScriptContext context)
{
// 检查并跳转到上次跳转的位置
if (parser.Evaluate<bool>(sentence.content))
{
if (context.GotoPointerStack.Count == 0)
{
throw new RScriptRuntimeException($"No position to back.", context.CurrentRuntimePointer);
}
else
{
DoJumpRuntimePointer(parser, context.GotoPointerStack.Pop(), context);
}
}
return null;
}
[return: MaybeNull]
public override IEnumerator RunAsync(ExpressionParser parser, RScriptSentence sentence, RScriptContext context)
{
// 检查并跳转到上次跳转的位置
if (parser.Evaluate<bool>(sentence.content))
{
if (context.GotoPointerStack.Count == 0)
{
throw new RScriptRuntimeException($"No position to back.", context.CurrentRuntimePointer);
}
else
{
DoJumpRuntimePointer(parser, context.GotoPointerStack.Pop(), context);
}
}
yield break;
}
}
}

View File

@@ -0,0 +1,59 @@
using Convention.RScript.Parser;
using System.Collections;
using System.Diagnostics.CodeAnalysis;
namespace Convention.RScript
{
public class BreakpointRunner : IRSentenceRunner
{
public void Compile(ExpressionParser parser, RScriptSentence sentence, RScriptContext context)
{
parser.Compile<bool>(sentence.content);
}
[return: MaybeNull]
public object Run(ExpressionParser parser, RScriptSentence sentence, RScriptContext context)
{
// 检查并跳转到当前命名空间的结束位置
if (parser.Evaluate<bool>(sentence.content))
{
if (context.RuntimePointerStack.Count == 0)
{
context.CurrentRuntimePointer = context.Sentences.Length;
}
else if (context.NamespaceLayer.TryGetValue(context.RuntimePointerStack.Peek(), out var exitPointer))
{
context.CurrentRuntimePointer = exitPointer;
return context.SentenceRunners[RScriptSentence.Mode.ExitNamespace].Run(parser, context.CurrentSentence, context);
}
else
{
throw new RScriptRuntimeException($"No namespace to break.", context.CurrentRuntimePointer);
}
}
return null;
}
[return: MaybeNull]
public IEnumerator RunAsync(ExpressionParser parser, RScriptSentence sentence, RScriptContext context)
{
// 检查并跳转到当前命名空间的结束位置
if (parser.Evaluate<bool>(sentence.content))
{
if (context.RuntimePointerStack.Count == 0)
{
context.CurrentRuntimePointer = context.Sentences.Length;
}
else if (context.NamespaceLayer.TryGetValue(context.RuntimePointerStack.Peek(), out var exitPointer))
{
context.CurrentRuntimePointer = exitPointer;
yield return context.SentenceRunners[RScriptSentence.Mode.ExitNamespace].RunAsync(parser, context.CurrentSentence, context);
}
else
{
throw new RScriptRuntimeException($"No namespace to break.", context.CurrentRuntimePointer);
}
}
}
}
}

View File

@@ -0,0 +1,186 @@
using Convention.RScript.Parser;
using System;
using System.Collections;
using System.Diagnostics.CodeAnalysis;
namespace Convention.RScript.Runner
{
public class DefineVariableRunner : IRSentenceRunner
{
public void Compile(ExpressionParser parser, RScriptSentence sentence, RScriptContext context)
{
var varTypeName = sentence.info[0];
var varName = sentence.info[1];
var varInitExpression = sentence.info[2];
Type varType;
object varDefaultValue;
{
if (varTypeName == "string")
{
varType = typeof(string);
varDefaultValue = "";
}
else if (varTypeName == "int")
{
varType = typeof(int);
if (varInitExpression != null) parser.Compile<int>(varInitExpression);
varDefaultValue = 0;
}
else if (varTypeName == "double")
{
varType = typeof(double);
if (varInitExpression != null) parser.Compile<double>(varInitExpression);
varDefaultValue = 0.0;
}
else if (varTypeName == "float")
{
varType = typeof(float);
if (varInitExpression != null) parser.Compile<float>(varInitExpression);
varDefaultValue = 0.0f;
}
else if (varTypeName == "bool")
{
varType = typeof(bool);
if (varInitExpression != null) parser.Compile<bool>(varInitExpression);
varDefaultValue = false;
}
else if (varTypeName == "var")
{
varType = typeof(object);
if (varInitExpression != null) parser.Compile(varInitExpression);
varDefaultValue = new object();
}
else
{
throw new RScriptRuntimeException($"Unsupported variable type '{varTypeName}'.", context.CurrentRuntimePointer);
}
}
if (context.CurrentLocalSpaceVariableNames.Peek().Contains(varName) == false)
{
context.Variables.Add(varName, new(varType, default));
parser.context.Variables[varName] = varDefaultValue;
context.CurrentLocalSpaceVariableNames.Peek().Add(varName);
}
else
{
throw new RScriptRuntimeException($"Variable '{varName}' already defined on this namespace.", context.CurrentRuntimePointer);
}
}
[return: MaybeNull]
public object Run(ExpressionParser parser, RScriptSentence sentence, RScriptContext context)
{
// 定义变量
var varTypeName = sentence.info[0];
var varName = sentence.info[1];
var varInitExpression = sentence.info[2];
Type varType;
object varDefaultValue;
{
if (varTypeName == "string")
{
varType = typeof(string);
varDefaultValue = varInitExpression == null ? string.Empty : varInitExpression.Trim('\"');
}
else if (varTypeName == "int")
{
varType = typeof(int);
varDefaultValue = varInitExpression == null ? 0 : Convert.ChangeType(parser.Evaluate(varInitExpression), typeof(int));
}
else if (varTypeName == "double")
{
varType = typeof(double);
varDefaultValue = varInitExpression == null ? 0.0 : Convert.ChangeType(parser.Evaluate(varInitExpression), typeof(double));
}
else if (varTypeName == "float")
{
varType = typeof(float);
varDefaultValue = varInitExpression == null ? 0.0f : Convert.ChangeType(parser.Evaluate(varInitExpression), typeof(float));
}
else if (varTypeName == "bool")
{
varType = typeof(bool);
varDefaultValue = varInitExpression == null ? false : Convert.ChangeType(parser.Evaluate(varInitExpression), typeof(bool));
}
else if (varTypeName == "var")
{
varType = typeof(object);
varDefaultValue = varInitExpression == null ? new object() : parser.Evaluate(varInitExpression);
}
else
{
throw new RScriptRuntimeException($"Unsupported variable type '{varTypeName}'.", context.CurrentRuntimePointer);
}
}
if (context.CurrentLocalSpaceVariableNames.Peek().Contains(varName) == false)
{
context.Variables.Add(varName, new(varType, varDefaultValue));
parser.context.Variables[varName] = varDefaultValue;
context.CurrentLocalSpaceVariableNames.Peek().Add(varName);
}
else
{
throw new RScriptRuntimeException($"Variable '{varName}' already defined on this namespace.", context.CurrentRuntimePointer);
}
return null;
}
[return: MaybeNull]
public IEnumerator RunAsync(ExpressionParser parser, RScriptSentence sentence, RScriptContext context)
{
// 定义变量
var varTypeName = sentence.info[0];
var varName = sentence.info[1];
var varInitExpression = sentence.info[2];
Type varType;
object varDefaultValue;
{
if (varTypeName == "string")
{
varType = typeof(string);
varDefaultValue = varInitExpression == null ? string.Empty : varInitExpression.Trim('\"');
}
else if (varTypeName == "int")
{
varType = typeof(int);
varDefaultValue = varInitExpression == null ? 0 : Convert.ChangeType(parser.Evaluate(varInitExpression), typeof(int));
}
else if (varTypeName == "double")
{
varType = typeof(double);
varDefaultValue = varInitExpression == null ? 0.0 : Convert.ChangeType(parser.Evaluate(varInitExpression), typeof(double));
}
else if (varTypeName == "float")
{
varType = typeof(float);
varDefaultValue = varInitExpression == null ? 0.0f : Convert.ChangeType(parser.Evaluate(varInitExpression), typeof(float));
}
else if (varTypeName == "bool")
{
varType = typeof(bool);
varDefaultValue = varInitExpression == null ? false : Convert.ChangeType(parser.Evaluate(varInitExpression), typeof(bool));
}
else if (varTypeName == "var")
{
varType = typeof(object);
varDefaultValue = varInitExpression == null ? new object() : parser.Evaluate(varInitExpression);
}
else
{
throw new RScriptRuntimeException($"Unsupported variable type '{varTypeName}'.", context.CurrentRuntimePointer);
}
}
if (context.CurrentLocalSpaceVariableNames.Peek().Contains(varName) == false)
{
context.Variables.Add(varName, new(varType, varDefaultValue));
parser.context.Variables[varName] = varDefaultValue;
context.CurrentLocalSpaceVariableNames.Peek().Add(varName);
}
else
{
throw new RScriptRuntimeException($"Variable '{varName}' already defined on this namespace.", context.CurrentRuntimePointer);
}
yield break;
}
}
}

View File

@@ -0,0 +1,28 @@
using Convention.RScript.Parser;
using System.Collections;
using System.Diagnostics.CodeAnalysis;
namespace Convention.RScript.Runner
{
public class EnterNamedSpaceRunner : IRSentenceRunner
{
public void Compile(ExpressionParser parser, RScriptSentence sentence, RScriptContext context)
{
}
[return: MaybeNull]
public object Run(ExpressionParser parser, RScriptSentence sentence, RScriptContext context)
{
context.CurrentRuntimePointer = context.NamespaceLayer[context.NamespaceLabels[sentence.content]];
return null;
}
[return: MaybeNull]
public IEnumerator RunAsync(ExpressionParser parser, RScriptSentence sentence, RScriptContext context)
{
context.CurrentRuntimePointer = context.NamespaceLayer[context.NamespaceLabels[sentence.content]];
yield break;
}
}
}

View File

@@ -0,0 +1,44 @@
using Convention.RScript.Parser;
using System.Collections;
using System.Diagnostics.CodeAnalysis;
namespace Convention.RScript.Runner
{
public class EnterNamespaceRunner : IRSentenceRunner
{
public void Compile(ExpressionParser parser, RScriptSentence sentence, RScriptContext context)
{
}
[return: MaybeNull]
public object Run(ExpressionParser parser, RScriptSentence sentence, RScriptContext context)
{
// 准备记录当前命名空间中定义的变量, 清空上层命名空间的变量
context.CurrentLocalSpaceVariableNames.Push(new());
// 更新变量值
foreach (var (varName, varValue) in parser.context.Variables)
{
context.Variables.SetValue(varName, varValue);
}
// 压栈
context.RuntimePointerStack.Push(context.CurrentRuntimePointer);
return null;
}
[return: MaybeNull]
public IEnumerator RunAsync(ExpressionParser parser, RScriptSentence sentence, RScriptContext context)
{
// 准备记录当前命名空间中定义的变量, 清空上层命名空间的变量
context.CurrentLocalSpaceVariableNames.Push(new());
// 更新变量值
foreach (var (varName, varValue) in parser.context.Variables)
{
context.Variables.SetValue(varName, varValue);
}
// 压栈
context.RuntimePointerStack.Push(context.CurrentRuntimePointer);
yield break;
}
}
}

View File

@@ -0,0 +1,68 @@
using Convention.RScript.Parser;
using System.Collections;
using System.Diagnostics.CodeAnalysis;
namespace Convention.RScript.Runner
{
public class ExitNamespaceRunner : IRSentenceRunner
{
public void Compile(ExpressionParser parser, RScriptSentence sentence, RScriptContext context)
{
}
[return: MaybeNull]
public object Run(ExpressionParser parser, RScriptSentence sentence, RScriptContext context)
{
// 移除当前命名空间的变量
foreach (var local in context.CurrentLocalSpaceVariableNames.Peek())
{
context.Variables.Remove(local);
parser.context.Variables.Remove(local);
}
// 还原上层命名空间的变量
foreach (var local in context.CurrentLocalSpaceVariableNames.Peek())
{
if (context.Variables.ContainsKey(local))
{
parser.context.Variables[local] = context.Variables[local].data;
}
else
{
parser.context.Variables.Remove(local);
}
}
context.CurrentLocalSpaceVariableNames.Pop();
// 弹栈
context.RuntimePointerStack.Pop();
return null;
}
[return: MaybeNull]
public IEnumerator RunAsync(ExpressionParser parser, RScriptSentence sentence, RScriptContext context)
{
// 移除当前命名空间的变量
foreach (var local in context.CurrentLocalSpaceVariableNames.Peek())
{
context.Variables.Remove(local);
parser.context.Variables.Remove(local);
}
// 还原上层命名空间的变量
foreach (var local in context.CurrentLocalSpaceVariableNames.Peek())
{
if (context.Variables.ContainsKey(local))
{
parser.context.Variables[local] = context.Variables[local].data;
}
else
{
parser.context.Variables.Remove(local);
}
}
context.CurrentLocalSpaceVariableNames.Pop();
// 弹栈
context.RuntimePointerStack.Pop();
yield break;
}
}
}

View File

@@ -0,0 +1,29 @@
using Convention.RScript.Parser;
using System.Collections;
using System.Diagnostics.CodeAnalysis;
namespace Convention.RScript.Runner
{
public class ExpressionRunner : IRSentenceRunner
{
public void Compile(ExpressionParser parser, RScriptSentence sentence, RScriptContext context)
{
parser.Compile(sentence.content);
}
[return: MaybeNull]
public object Run(ExpressionParser parser, RScriptSentence sentence, RScriptContext context)
{
return parser.Evaluate(sentence.content);
}
[return: MaybeNull]
public IEnumerator RunAsync(ExpressionParser parser, RScriptSentence sentence, RScriptContext context)
{
var result = parser.Evaluate(sentence.content);
if(result is IEnumerator ir)
yield return ir;
yield return null;
}
}
}

91
DoRunner/GoToRunner.cs Normal file
View File

@@ -0,0 +1,91 @@
using Convention.RScript.Parser;
using System.Collections;
using System.Diagnostics.CodeAnalysis;
namespace Convention.RScript.Runner
{
public class GoToRunner : JumpRuntimePointerRunner
{
public override void Compile(ExpressionParser parser, RScriptSentence sentence, RScriptContext context)
{
parser.Compile<bool>(sentence.info[0]);
}
[return: MaybeNull]
public override object Run(ExpressionParser parser, RScriptSentence sentence, RScriptContext context)
{
// 检查并跳转到指定标签
if (parser.Evaluate<bool>(sentence.info[0]))
{
if (context.Labels.TryGetValue(sentence.content, out var labelPointer))
{
context.GotoPointerStack.Push(context.CurrentRuntimePointer);
DoJumpRuntimePointer(parser, labelPointer, context);
}
else if (context.NamespaceLabels.TryGetValue(sentence.content, out labelPointer))
{
int current = context.CurrentRuntimePointer;
//DoEnterNamespace(parser);
context.SentenceRunners[RScriptSentence.Mode.EnterNamespace].Run(parser, context.CurrentSentence, context);
context.CurrentRuntimePointer = labelPointer;
for (int e = context.NamespaceLayer[context.NamespaceLabels[sentence.content]]; ;)
{
context.RunNextStep(parser);
if (context.CurrentRuntimePointer >= context.Sentences.Length)
break;
else if (context.CurrentRuntimePointer == e)
break;
else
context.CurrentRuntimePointer++;
}
//context.DoExitNamespace(parser);
context.SentenceRunners[RScriptSentence.Mode.ExitNamespace].Run(parser, context.CurrentSentence, context);
context.CurrentRuntimePointer = current;
}
else
{
throw new RScriptRuntimeException($"Label '{sentence.content}' not found.", context.CurrentRuntimePointer);
}
}
return null;
}
[return: MaybeNull]
public override IEnumerator RunAsync(ExpressionParser parser, RScriptSentence sentence, RScriptContext context)
{
// 检查并跳转到指定标签
if (parser.Evaluate<bool>(sentence.info[0]))
{
if (context.Labels.TryGetValue(sentence.content, out var labelPointer))
{
context.GotoPointerStack.Push(context.CurrentRuntimePointer);
DoJumpRuntimePointer(parser, labelPointer, context);
}
else if (context.NamespaceLabels.TryGetValue(sentence.content, out labelPointer))
{
int current = context.CurrentRuntimePointer;
//DoEnterNamespace(parser);
context.SentenceRunners[RScriptSentence.Mode.EnterNamespace].Run(parser, context.CurrentSentence, context);
context.CurrentRuntimePointer = labelPointer;
for (int e = context.NamespaceLayer[context.NamespaceLabels[sentence.content]]; ;)
{
yield return context.RunNextStepAsync(parser);
if (context.CurrentRuntimePointer >= context.Sentences.Length)
break;
else if (context.CurrentRuntimePointer == e)
break;
else
context.CurrentRuntimePointer++;
}
//context.DoExitNamespace(parser);
context.SentenceRunners[RScriptSentence.Mode.ExitNamespace].Run(parser, context.CurrentSentence, context);
context.CurrentRuntimePointer = current;
}
else
{
throw new RScriptRuntimeException($"Label '{sentence.content}' not found.", context.CurrentRuntimePointer);
}
}
}
}
}

View File

@@ -0,0 +1,79 @@
using Convention.RScript.Parser;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace Convention.RScript.Runner
{
public abstract class JumpRuntimePointerRunner : IRSentenceRunner
{
protected static void DoJumpRuntimePointer(ExpressionParser parser, int target, RScriptContext context)
{
Tuple<int, int> enterKey = Tuple.Create(context.CurrentRuntimePointer, target);
int currentPointer = context.CurrentRuntimePointer;
int depth = 0;
int lastLayer = 0;
if (context.JumpPointerCache.TryGetValue(enterKey, out var jumpResult))
{
depth = jumpResult.Item1;
lastLayer = jumpResult.Item2;
context.CurrentRuntimePointer = target;
}
else
{
bool isForwardMove = target > context.CurrentRuntimePointer;
int step = isForwardMove ? 1 : -1;
for (; context.CurrentRuntimePointer != target; context.CurrentRuntimePointer += step)
{
if (context.CurrentSentence.mode == RScriptSentence.Mode.ExitNamespace)
{
if (isForwardMove)
lastLayer--;
else
lastLayer++;
}
else if (context.CurrentSentence.mode == RScriptSentence.Mode.EnterNamespace)
{
if (isForwardMove)
lastLayer++;
else
lastLayer--;
}
depth = lastLayer < depth ? lastLayer : depth;
}
context.JumpPointerCache.Add(enterKey, Tuple.Create(depth, lastLayer));
}
// 对上层的最深影响
for (; depth < 0; depth++)
{
try
{
context.SentenceRunners[RScriptSentence.Mode.ExitNamespace].Run(parser, context.CurrentSentence, context);
}
catch (Exception ex)
{
throw new RScriptRuntimeException($"Jump pointer with error", currentPointer, ex);
}
}
// 恢复正确的层数
for (int i = depth, e = lastLayer; i < e; i++)
{
try
{
context.SentenceRunners[RScriptSentence.Mode.EnterNamespace].Run(parser, context.CurrentSentence, context);
}
catch (Exception ex)
{
throw new RScriptRuntimeException($"Jump pointer with error", currentPointer, ex);
}
}
}
public abstract void Compile(ExpressionParser parser, RScriptSentence sentence, RScriptContext context);
[return: MaybeNull]
public abstract object Run(ExpressionParser parser, RScriptSentence sentence, RScriptContext context);
[return: MaybeNull]
public abstract IEnumerator RunAsync(ExpressionParser parser, RScriptSentence sentence, RScriptContext context);
}
}

View File

@@ -4,16 +4,29 @@ namespace Convention.RScript.Matcher
{
public class DefineVariableMatcher : IRSentenceMatcher
{
private readonly Regex DefineVariableRegex = new(@"(string|int|double|float|bool|var)\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.+)");
private readonly Regex DeclareVariableRegex = new(@"(string|int|double|float|bool|var)\s+([a-zA-Z_][a-zA-Z0-9_]*)");
public bool Match(string expression, ref RScriptSentence sentence)
{
Regex DefineVariableRegex = new(@"(string|int|double|float|bool|var)\s+([a-zA-Z_][a-zA-Z0-9_]*)");
{
var DefineVariableMatch = DefineVariableRegex.Match(expression);
if (DefineVariableMatch.Success)
{
sentence.mode = RScriptSentence.Mode.DefineVariable;
sentence.info = new() { DefineVariableMatch.Groups[1].Value, DefineVariableMatch.Groups[2].Value };
sentence.info = new[] { DefineVariableMatch.Groups[1].Value, DefineVariableMatch.Groups[2].Value, DefineVariableMatch.Groups[3].Value };
return true;
}
}
{
var DeclareVariableMatch = DeclareVariableRegex.Match(expression);
if (DeclareVariableMatch.Success)
{
sentence.mode = RScriptSentence.Mode.DefineVariable;
sentence.info = new[] { DeclareVariableMatch.Groups[1].Value, DeclareVariableMatch.Groups[2].Value, null };
return true;
}
}
return false;
}
}

View File

@@ -13,7 +13,7 @@ namespace Convention.RScript.Matcher
{
sentence.mode = RScriptSentence.Mode.Goto;
sentence.content = GotoMatch.Groups[2].Value;
sentence.info = new() { GotoMatch.Groups[1].Value, GotoMatch.Groups[2].Value };
sentence.info = new[] { GotoMatch.Groups[1].Value, GotoMatch.Groups[2].Value };
return true;
}
return false;

View File

@@ -1,4 +1,6 @@
namespace Convention.RScript.Matcher
using System.Text.RegularExpressions;
namespace Convention.RScript.Matcher
{
public class NamespaceMater : IRSentenceMatcher
{
@@ -14,6 +16,21 @@
sentence.mode = RScriptSentence.Mode.ExitNamespace;
return true;
}
else if (expression.StartsWith("namespace"))
{
sentence.mode = RScriptSentence.Mode.NamedSpace;
Regex regex = new(@"namespace\s*\(([a-zA-Z_][a-zA-Z0-9_]*)\)");
var match = regex.Match(expression);
if (match.Success)
{
sentence.content = match.Groups[1].Value;
return true;
}
else
{
throw new RScriptRuntimeException("Invalid namespace declaration", -1);
}
}
return false;
}
}

View File

@@ -1,12 +1,65 @@
using Flee.PublicTypes;
using System;
using System.Collections.Generic;
using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
namespace Convention.RScript.Parser
namespace Convention.RScript
{
public static class ExpressionMath
{
public static int Sign(double value, double accuracy = ExpressionExtension.DefaultDoubleAccuracy)
{
if (value.IsCloseToZero(accuracy))
return 0;
return value > 0 ? 1 : -1;
}
public static int Compare(double value1, double value2, double accuracy = ExpressionExtension.DefaultDoubleAccuracy)
{
if (value1.IsClose(value2, accuracy))
return 0;
return value1 > value2 ? 1 : -1;
}
public static bool IsBetween(double value, double minValue, double maxValue, double accuracy = ExpressionExtension.DefaultDoubleAccuracy)
{
return Compare(value, minValue, accuracy) >= 0 && Compare(value, maxValue, accuracy) <= 0;
}
public static bool IsBetweenExclusive(double value, double minValue, double maxValue, double accuracy = ExpressionExtension.DefaultDoubleAccuracy)
{
return Compare(value, minValue, accuracy) > 0 && Compare(value, maxValue, accuracy) < 0;
}
public static int ToInt(double value)
{
return (int)value;
}
public static int ToInt(float value)
{
return (int)value;
}
public static int ToInt(int value)
{
return (int)value;
}
public static double ToDouble(float value)
{
return (double)value;
}
public static double ToDouble(int value)
{
return (double)value;
}
public static double ToDouble(double value)
{
return (double)value;
}
}
public static class ExpressionExtension
{
public const double DefaultDoubleAccuracy = 1e-7;
@@ -32,7 +85,10 @@ namespace Convention.RScript.Parser
return !(double.IsInfinity(value) || double.IsNaN(value) || value > maximumAbsoluteError || value < -maximumAbsoluteError);
}
}
}
namespace Convention.RScript.Parser
{
public class ExpressionParser
{
public readonly ExpressionContext context;
@@ -40,8 +96,19 @@ namespace Convention.RScript.Parser
public ExpressionParser(ExpressionContext context)
{
this.context = context;
// 默认启用未定义标识符作为字符串的功能
this.context.Options.UndefinedIdentifiersAsStrings = true;
// 启用大小写敏感
this.context.Options.CaseSensitive = true;
// 启用溢出检查
this.context.Options.Checked = true;
#if UNITY_EDITOR
// 浮点数使用float而非doubleUnity性能优化
this.context.Options.RealLiteralDataType = RealLiteralDataType.Single;
#endif
}
private readonly Dictionary<string, Type> CompileGenericExpressionTypen = new();
private readonly Dictionary<string, IExpression> CompileGenericExpression = new();
private readonly Dictionary<string, IDynamicExpression> CompileDynamicExpression = new();
@@ -55,11 +122,12 @@ namespace Convention.RScript.Parser
{
if (CompileGenericExpression.TryGetValue(expression, out var result))
{
return (result as IGenericExpression<T>).Evaluate();
if (result is IGenericExpression<T> genericExpression)
return genericExpression.Evaluate();
else
return context.CompileGeneric<T>(expression).Evaluate();
}
var compile = context.CompileGeneric<T>(expression);
CompileGenericExpression[expression] = compile;
return compile.Evaluate();
return Compile<T>(expression).Evaluate();
}
public object Evaluate(string expression)
@@ -68,9 +136,77 @@ namespace Convention.RScript.Parser
{
return result.Evaluate();
}
return Compile(expression).Evaluate();
}
public IGenericExpression<T> Compile<T>(string expression)
{
var compile = context.CompileGeneric<T>(expression);
CompileGenericExpression[expression] = compile;
CompileGenericExpressionTypen[expression] = typeof(T);
return compile;
}
public IDynamicExpression Compile(string expression)
{
var compile = context.CompileDynamic(expression);
CompileDynamicExpression[expression] = compile;
return compile.Evaluate();
return compile;
}
[Serializable]
public struct SerializableParser
{
public Tuple<string, string>[] CompileGenericExpression;
public string[] CompileDynamicExpression;
}
public SerializableParser Serialize()
{
return new()
{
CompileGenericExpression = (from key in CompileGenericExpression.Keys select Tuple.Create(CompileGenericExpressionTypen[key].Name, key)).ToArray(),
CompileDynamicExpression = CompileDynamicExpression.Keys.ToArray()
};
}
public void Deserialize(SerializableParser data)
{
foreach (var (type, expr) in data.CompileGenericExpression)
{
if (type == nameof(String))
{
this.Compile<string>(expr);
}
else if (type == nameof(Single))
{
this.Compile<float>(expr);
}
else if (type == nameof(Double))
{
this.Compile<double>(expr);
}
else if (type == nameof(Int32))
{
this.Compile<int>(expr);
}
else if (type == nameof(Boolean))
{
this.Compile<bool>(expr);
}
else if (type == nameof(Object))
{
this.Compile<object>(expr);
}
else
{
throw new NotSupportedException($"Unsupported expression type: {type}");
}
}
foreach (var expr in data.CompileDynamicExpression)
{
this.Compile(expr);
}
}
}
}

View File

@@ -0,0 +1,189 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Convention.RScript.Variable.CStyle
{
public class CScriptRScriptVariableGenerater : RScriptInjectVariableGenerater
{
/// <summary>
/// 获取类型的友好显示名称,支持泛型、数组等复杂类型
/// </summary>
public static string GetFriendlyName(Type type)
{
if (type == null) return null;
// 处理泛型类型
if (type.IsGenericType)
{
// 特殊处理可空类型Nullable<T>
if (type.IsNullable())
{
return $"{GetFriendlyName(type.GetGenericArguments()[0])}?";
}
var sb = new StringBuilder();
// 获取类型基础名称(移除 `1, `2 等后缀)
string baseName = type.Name.Contains('`') ? type.Name[..type.Name.IndexOf('`')] : type.Name;
sb.Append(baseName);
sb.Append('<');
// 递归处理泛型参数
Type[] args = type.GetGenericArguments();
for (int i = 0; i < args.Length; i++)
{
if (i > 0) sb.Append(", ");
sb.Append(GetFriendlyName(args[i]));
}
sb.Append('>');
return sb.ToString();
}
// 处理数组类型
if (type.IsArray)
{
string elementName = GetFriendlyName(type.GetElementType());
int rank = type.GetArrayRank();
return rank == 1 ? $"{elementName}[]" : $"{elementName}[{new string(',', rank - 1)}]";
}
// 处理指针类型
if (type.IsPointer)
{
return $"{GetFriendlyName(type.GetElementType())}*";
}
// 处理引用类型ref/out 参数)
if (type.IsByRef)
{
return $"{GetFriendlyName(type.GetElementType())}&";
}
// 普通类型直接返回名称
return type.Name;
}
/// <summary>
/// 判断是否为可空类型
/// </summary>
public static bool IsNullable(Type type)
{
return type.IsGenericType &&
type.GetGenericTypeDefinition() == typeof(Nullable<>);
}
public static string GetTypename(Type type)
{
if (type == typeof(int))
return "int";
if (type == typeof(float))
return "float";
if (type == typeof(double))
return "double";
if (type == typeof(bool))
return "bool";
if (type == typeof(void))
return "void";
return GetFriendlyName(type).Replace('`', '_');
}
private int m_layer = 0;
private int layer
{
get=>m_layer;
set
{
m_layer = value;
Prefix = new('\t', layer);
}
}
private string Prefix = "";
public CScriptRScriptVariableGenerater(Type targetType, Generater generater, Destorier destorier, string name) : base(targetType, generater, destorier, name)
{
}
protected override string WriteClassBodyEnter(Type currentType)
{
string result = $"{Prefix}{"{"}\n{Prefix}public:";
layer++;
return result;
}
protected override string WriteClassBodyExit(Type currentType)
{
layer--;
return $"{Prefix}{"};"}";
}
protected override string WriteClassHead(Type currentType)
{
string description = string.IsNullOrEmpty(this.description) ? "" : string.Join("", from item in this.description.Split('\n') where string.IsNullOrEmpty(item) == false select $"{Prefix}{item}\n");
string suffix = currentType.BaseType == typeof(object) ? string.Empty : $" : public {GetTypename(currentType.BaseType)}";
string result = $"{Prefix}\\*{description}*\\\n{Prefix}{Prefix}class {GetTypename(currentType)}{suffix}";
return result;
}
protected override string WriteClassMethod(Type returnType, string methodName, string[] parameterNames, Type[] parameterTypes)
{
List<string> parameters = new();
for (int i = 0, e = parameterNames.Length; i < e; i++)
{
parameters.Add($"{GetTypename(parameterTypes[i])} {parameterNames[i]}");
}
return $"{Prefix}{GetTypename(returnType)} {methodName}({string.Join(", ", parameters)});";
}
protected override string WriteClassTail(Type currentType)
{
return "";
}
protected override string WriteEnumBodyEnter(Type currentType)
{
string result = $"{Prefix}{"{"}";
layer++;
return result;
}
protected override string WriteEnumBodyExit(Type currentType)
{
layer--;
return $"{Prefix}{"};"}";
}
protected override string WriteEnumHead(Type currentEnum)
{
return $"{Prefix}enum {GetTypename(currentEnum)}";
}
protected override string WriteEnumName(string enumName)
{
return $"{Prefix}{enumName},";
}
protected override string WriteEnumTail(Type currentType)
{
return "";
}
protected override string WritePageEnd(Type currentType)
{
return "";
}
protected override string WritePageHead(Type currentType)
{
if (currentType.BaseType != null)
return $"#include\"{GetFilename(currentType.BaseType)}\"";
return string.Empty;
}
public override string GetFilename(Type currentType)
{
return GetTypename(currentType);
}
}
}

View File

@@ -2,10 +2,26 @@
namespace Convention.RScript
{
[Serializable]
public class RScriptException : Exception
{
public RScriptException(string message, int runtimePointer) : base($"when running {runtimePointer}, {message}") { }
public RScriptException(string message, int runtimePointer, Exception inner) : base($"when running {runtimePointer}, {message}", inner) { }
public RScriptException() { }
public RScriptException(string message) : base(message) { }
public RScriptException(string message, Exception inner) : base(message, inner) { }
}
[Serializable]
public class RScriptRuntimeException : RScriptException
{
public RScriptRuntimeException(string message, int runtimePointer) : base($"when running {runtimePointer}, {message}") { }
public RScriptRuntimeException(string message, int runtimePointer, Exception inner) : base($"when running {runtimePointer}, {message}", inner) { }
}
[Serializable]
public class RScriptCompileException : RScriptException
{
public RScriptCompileException(string message, int line, int chIndex) : base($"when compile on line {line} char {chIndex}, {message}") { }
public RScriptCompileException(string message, int line, int chIndex, Exception inner) : base($"when compile on line {line} char {chIndex}, {message}", inner) { }
}
}

View File

@@ -0,0 +1,273 @@
using Flee.InternalTypes;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Text;
namespace Convention.RScript.Variable
{
namespace Attr
{
[AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public sealed class MethodAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Enum, Inherited = true, AllowMultiple = false)]
public sealed class EnumAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Struct, Inherited = false, AllowMultiple = false)]
public sealed class DefaultAttribute : Attribute
{
public string defaultScript;
public DefaultAttribute(string defaultScript)
{
this.defaultScript = defaultScript;
}
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false, AllowMultiple = false)]
public sealed class DescriptionAttribute : Attribute
{
public string description;
public DescriptionAttribute(string description)
{
this.description = description;
}
}
}
public abstract class RScriptInjectVariableGenerater
{
public string RScriptString { get; private set; }
public abstract string GetFilename(Type currentType);
protected abstract string WritePageHead(Type currentType);
#region Enum
protected abstract string WriteEnumHead(Type currentEnum);
protected abstract string WriteEnumBodyEnter(Type currentType);
protected abstract string WriteEnumName(string enumName);
protected abstract string WriteEnumBodyExit(Type currentType);
protected abstract string WriteEnumTail(Type currentType);
#endregion
#region Class
protected abstract string WriteClassHead(Type currentType);
protected abstract string WriteClassBodyEnter(Type currentType);
protected abstract string WriteClassMethod(Type returnType, string methodName, string[] parameterNames, Type[] parameterTypes);
protected abstract string WriteClassBodyExit(Type currentType);
protected abstract string WriteClassTail(Type currentType);
#endregion
protected abstract string WritePageEnd(Type currentType);
/// <summary>
/// 生成targetType类型的实体
/// </summary>
/// <returns></returns>
public delegate object Generater();
public delegate void Destorier(object o);
private readonly Generater MyGenerater;
private readonly Destorier MyDestorier;
private readonly HashSet<object> GenerateObjects = new();
public readonly static Dictionary<string, RScriptInjectVariableGenerater> AllRScriptInjectVariables = new();
public readonly Type targetType;
public readonly string name;
public readonly string scriptIndicator;
public readonly string defaultScript;
public readonly string description;
public object Generate()
{
return MyGenerater();
}
public RScriptInjectVariableGenerater(Type targetType, [MaybeNull] Generater generater, [MaybeNull] Destorier destorier, string name)
{
if (AllRScriptInjectVariables.TryGetValue(name, out var exist_var))
{
throw new InvalidOperationException($"{name} is been used");
}
this.targetType = targetType;
this.MyGenerater = generater;
this.MyDestorier = destorier;
this.name = name;
var defaultAttr = targetType.GetCustomAttribute<Attr.DefaultAttribute>();
this.defaultScript = defaultAttr?.defaultScript ?? "";
var descriptionAttr = targetType.GetCustomAttribute<Attr.DescriptionAttribute>();
this.description = descriptionAttr?.description ?? "";
StringBuilder builder = new();
builder.AppendLine(this.WritePageHead(targetType));
if (targetType.IsEnum)
{
// 绘制枚举
builder.AppendLine(this.WriteEnumHead(targetType));
builder.AppendLine(this.WriteEnumBodyEnter(targetType));
foreach (var enumName in targetType.GetEnumNames())
{
builder.AppendLine(this.WriteEnumName(enumName));
}
builder.AppendLine(this.WriteEnumBodyExit(targetType));
builder.AppendLine(this.WriteEnumTail(targetType));
}
else
{
builder.AppendLine(this.WriteClassHead(targetType));
builder.AppendLine(this.WriteClassBodyEnter(targetType));
// 绘制枚举
{
var scriptEnums = from enumItem in targetType.GetNestedTypes(BindingFlags.NonPublic | BindingFlags.Public)
where enumItem.GetCustomAttribute<Attr.EnumAttribute>() != null
select enumItem;
foreach (var enumItem in scriptEnums)
{
var attr = enumItem.GetCustomAttribute<Attr.EnumAttribute>();
this.WriteEnumHead(targetType);
this.WriteEnumBodyEnter(targetType);
foreach (var enumName in enumItem.GetEnumNames())
{
this.WriteEnumName(enumName);
}
this.WriteEnumBodyExit(targetType);
this.WriteEnumTail(targetType);
}
}
// 绘制方法
{
var scriptMethods = from method in targetType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly)
where method.GetCustomAttribute<Attr.MethodAttribute>() != null
select method;
foreach (var method in scriptMethods)
{
var attr = method.GetCustomAttribute<Attr.MethodAttribute>();
var returnType = method.ReturnType;
var methodName = method.Name;
var parameters = method.GetParameters();
var parameterNames = from item in parameters select item.Name;
var parameterTypes = from item in parameters select item.ParameterType;
builder.AppendLine(this.WriteClassMethod(returnType, methodName, parameterNames.ToArray(), parameterTypes.ToArray()));
}
}
builder.AppendLine(this.WriteClassBodyExit(targetType));
builder.AppendLine(this.WriteClassTail(targetType));
}
builder.AppendLine(this.WritePageEnd(targetType));
this.scriptIndicator = builder.ToString();
}
public void Register()
{
AllRScriptInjectVariables.Add(name, this);
}
public bool Unregister()
{
if (MyDestorier != null)
foreach (var item in GenerateObjects)
{
MyDestorier(item);
}
this.GenerateObjects.Clear();
return AllRScriptInjectVariables.Remove(name);
}
public class EnumGetter
{
public Type enumType;
public EnumGetter(Type enumType)
{
this.enumType = enumType;
}
public object Get(string name)
{
return Enum.Parse(enumType, name);
}
}
public static object GenerateRScriptVariable(string name)
{
if (AllRScriptInjectVariables.TryGetValue(name, out var variable))
{
if (variable.targetType.IsEnum)
{
if (variable.MyGenerater != null)
{
var result = variable.Generate();
if (result.GetType().IsSubclassOf(variable.targetType) || result.GetType() == variable.targetType)
{
variable.GenerateObjects.Add(result);
return result;
}
else
throw new InvalidOperationException($"{name} target is not sub-class of it's target type");
}
else
{
return variable.targetType;
}
}
else
{
if (variable.MyGenerater != null)
{
var result = variable.Generate();
if (result.GetType().IsSubclassOf(variable.targetType) || result.GetType() == variable.targetType)
{
variable.GenerateObjects.Add(result);
return result;
}
else
throw new InvalidOperationException($"{name} target is not sub-class of it's target type");
}
}
}
throw new InvalidOperationException($"{name} target is not exist or abstract");
}
public static string DestoryRScriptVariable(object o)
{
if (o == null)
return string.Empty;
foreach (var (name,variable) in AllRScriptInjectVariables)
{
variable.GenerateObjects.RemoveWhere(x => x == null);
if(variable.GenerateObjects.Remove(o))
{
variable.MyDestorier(o);
return variable.name;
}
}
return string.Empty;
}
}
public static class RScriptVariableGenerater
{
public static object New(string name)
{
return RScriptInjectVariableGenerater.GenerateRScriptVariable(name);
}
public static string Delete(object o)
{
return RScriptInjectVariableGenerater.DestoryRScriptVariable(o);
}
}
}

View File

@@ -11,7 +11,40 @@ namespace Convention.RScript
public struct RScriptVariableEntry
{
public Type type;
public object data;
public object data
{
readonly get
{
return internalData;
}
set
{
if (type == null)
{
type = value.GetType();
internalData = value;
return;
}
if (value == null)
{
if (type.IsClass)
internalData = null;
else
internalData = Activator.CreateInstance(type);
}
else if (type == typeof(object) || type.IsAssignableFrom(value.GetType()))
internalData = value;
else
internalData = Convert.ChangeType(value, type);
}
}
private object internalData;
public RScriptVariableEntry(Type type, object data) : this()
{
this.type = type;
this.data = data;
}
}
public class RScriptVariables : IDictionary<string, RScriptVariableEntry>
{

View File

@@ -1,2 +1,2 @@
需要与 http://www.liubai.site:3000/ninemine/Flee.git 一起工作
需要与 http://gitea.liubai.site/ninemine/Flee.git 一起工作

View File

@@ -1,14 +1,19 @@
using Convention.RScript.Matcher;
using Convention.RScript.Parser;
using Convention.RScript.Runner;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using static Convention.RScript.RScriptContext;
namespace Convention.RScript
{
[Serializable]
public struct RScriptSentence
{
[Serializable]
public enum Mode
{
/// <summary>
@@ -16,7 +21,7 @@ namespace Convention.RScript
/// </summary>
Expression,
/// <summary>
/// 定义变量, 格式: 类型 变量名
/// 定义变量, 格式: 类型 变量名 [=Expression]
/// <para>类型支持: string, int, double, float, bool, var</para>
/// <para>每层命名空间中不可重复定义变量, 不可使用未定义的变量, 不存在时会自动向上查找上级空间的变量</para>
/// </summary>
@@ -32,11 +37,11 @@ namespace Convention.RScript
/// </summary>
ExitNamespace,
/// <summary>
/// 标签, 格式: label(labelname)
/// 标签, 格式: label(labelname);
/// </summary>
Label,
/// <summary>
/// 跳转到指定标签, 格式: goto(boolean,labelname)
/// 跳转到指定标签, 格式: goto(boolean,labelname);
/// <para>判断为真时跳转到labelname</para>
/// </summary>
Goto,
@@ -48,11 +53,20 @@ namespace Convention.RScript
/// 跳转到上次跳转的位置的后一个位置, 格式: back(boolean);
/// </summary>
Backpoint,
/// <summary>
/// 命名空间命名, 格式: namespace(labelname){}
/// </summary>
NamedSpace,
}
public string content;
public List<string> info;
public string[] info;
public Mode mode;
public override readonly string ToString()
{
return $"{mode}: {content}";
}
}
public interface IRSentenceMatcher
@@ -60,13 +74,49 @@ namespace Convention.RScript
bool Match(string expression, ref RScriptSentence sentence);
}
public partial class RScriptContext
public interface IRSentenceRunner
{
public readonly RScriptImportClass Import;
public readonly RScriptVariables Variables;
private readonly RScriptSentence[] Sentences;
private readonly Dictionary<string, int> Labels;
private readonly Dictionary<int, int> Namespace;
[return: MaybeNull] object Run(ExpressionParser parser, RScriptSentence sentence, RScriptContext context);
[return: MaybeNull] IEnumerator RunAsync(ExpressionParser parser, RScriptSentence sentence, RScriptContext context);
void Compile(ExpressionParser parser, RScriptSentence sentence, RScriptContext context);
}
public interface IBasicRScriptContext
{
RScriptImportClass Import { get; }
RScriptVariables Variables { get; }
RScriptSentence[] Sentences { get; }
int CurrentRuntimePointer { get; }
RScriptSentence CurrentSentence { get; }
Dictionary<string, RScriptVariableEntry> GetCurrentVariables();
void Run(ExpressionParser parser);
IEnumerator RunAsync(ExpressionParser parser);
public void ReRun(ExpressionParser parser);
public IEnumerator ReRunAsync(ExpressionParser parser);
SerializableClass Compile(ExpressionParser parser);
SerializableClass CompileFromCurrent(ExpressionParser parser);
}
public partial class RScriptContext : IBasicRScriptContext
{
public RScriptImportClass Import { get;private set; }
public RScriptVariables Variables { get;private set; }
public RScriptSentence[] Sentences { get; private set; }
internal readonly Dictionary<string, int> Labels = new();
internal readonly Dictionary<int, int> NamespaceLayer = new();
internal readonly Dictionary<string, int> NamespaceLabels = new();
[Serializable]
public struct SerializableClass
{
public RScriptSentence[] Sentences;
public Tuple<string, int>[] Labels;
public Tuple<int, int>[] NamespaceLayer;
public Tuple<string, int>[] NamespaceLabels;
//public ExpressionParser.SerializableParser CompileParser;
public Tuple<Tuple<int, int>, Tuple<int, int>>[] JumpPointerCache;
}
public List<IRSentenceMatcher> SentenceParser = new()
{
@@ -78,6 +128,18 @@ namespace Convention.RScript
new BackMatcher(),
};
public Dictionary<RScriptSentence.Mode, IRSentenceRunner> SentenceRunners = new()
{
{ RScriptSentence.Mode.DefineVariable, new DefineVariableRunner() },
{ RScriptSentence.Mode.EnterNamespace, new EnterNamespaceRunner() },
{ RScriptSentence.Mode.ExitNamespace, new ExitNamespaceRunner() },
{ RScriptSentence.Mode.Goto, new GoToRunner() },
{ RScriptSentence.Mode.Breakpoint, new BreakpointRunner() },
{ RScriptSentence.Mode.Backpoint, new BackpointRunner() },
{ RScriptSentence.Mode.Expression, new ExpressionRunner() },
{ RScriptSentence.Mode.NamedSpace, new EnterNamedSpaceRunner() },
};
private RScriptSentence ParseToSentence(string expression)
{
RScriptSentence result = new()
@@ -86,262 +148,153 @@ namespace Convention.RScript
mode = RScriptSentence.Mode.Expression
};
expression = expression.Trim();
expression.TrimEnd(';');
SentenceParser.Any(matcher => matcher.Match(expression, ref result));
expression = expression.TrimEnd(';');
var _ = SentenceParser.Any(matcher => matcher.Match(expression, ref result));
return result;
}
private void BuildUpLabelsAndNamespace(ref Dictionary<string, int> labelIndicator, ref Dictionary<int, int> namespaceIndicator)
private void BuildUpLabelsAndNamespace()
{
Stack<int> namespaceLayers = new();
string namespaceName = "";
for (int i = 0, e = Sentences.Length; i != e; i++)
{
if (Sentences[i].mode == RScriptSentence.Mode.Label)
var sentence = Sentences[i];
if (string.IsNullOrEmpty(namespaceName))
{
labelIndicator[Sentences[i].content] = i;
if (sentence.mode == RScriptSentence.Mode.Label)
{
this.Labels[Sentences[i].content] = i;
}
else if (Sentences[i].mode == RScriptSentence.Mode.EnterNamespace)
else if (sentence.mode == RScriptSentence.Mode.EnterNamespace)
{
namespaceLayers.Push(i);
}
else if (Sentences[i].mode == RScriptSentence.Mode.ExitNamespace)
else if (sentence.mode == RScriptSentence.Mode.ExitNamespace)
{
if (namespaceLayers.Count == 0)
throw new RScriptException("Namespace exit without enter.", i);
throw new RScriptRuntimeException("Namespace exit without enter.", i);
var enterPointer = namespaceLayers.Pop();
namespaceIndicator[enterPointer] = i;
this.NamespaceLayer[enterPointer] = i;
}
else if (sentence.mode == RScriptSentence.Mode.NamedSpace)
{
namespaceName = sentence.content;
}
}
else
{
if (sentence.mode == RScriptSentence.Mode.EnterNamespace)
{
namespaceLayers.Push(i);
this.NamespaceLabels[namespaceName] = i;
namespaceName = "";
}
else
{
throw new RScriptRuntimeException($"Namespace is invalid", i);
}
}
}
if (namespaceLayers.Count > 0)
{
throw new RScriptException("Namespace enter without exit.", namespaceLayers.Peek());
throw new RScriptRuntimeException("Namespace enter without exit.", namespaceLayers.Peek());
}
}
public RScriptContext(string[] expressions, RScriptImportClass import = null, RScriptVariables variables = null)
public class BuildInContext
{
private RScriptContext context;
public BuildInContext(RScriptContext context)
{
this.context = context;
}
public bool ExistVar(string name)
{
return context.Variables.ContainsKey(name);
}
public bool ExistNamespace(string name)
{
return context.NamespaceLabels.ContainsKey(name);
}
public bool ExistLabel(string name)
{
return context.Labels.ContainsKey(name);
}
}
public RScriptContext(string[] expressions,
RScriptImportClass import = null,
RScriptVariables variables = null,
List<IRSentenceMatcher> matcher = null,
Dictionary<RScriptSentence.Mode, IRSentenceRunner> sentenceRunners = null)
{
this.Import = import ?? new();
this.Variables = variables ?? new();
this.Variables.Add("context", new(typeof(object), new BuildInContext(this)));
this.Sentences = (from item in expressions select ParseToSentence(item)).ToArray();
this.Labels = new();
this.Namespace = new();
BuildUpLabelsAndNamespace(ref this.Labels, ref this.Namespace);
if (matcher != null)
this.SentenceParser = matcher;
if (sentenceRunners != null)
this.SentenceRunners = sentenceRunners;
BuildUpLabelsAndNamespace();
}
public RScriptContext(SerializableClass data,
RScriptImportClass import = null,
RScriptVariables variables = null,
List<IRSentenceMatcher> matcher = null,
Dictionary<RScriptSentence.Mode, IRSentenceRunner> sentenceRunners = null)
{
this.Import = import ?? new();
this.Variables = variables ?? new();
this.Variables.Add("context", new(typeof(object), new BuildInContext(this)));
this.Sentences = data.Sentences;
if (data.Labels != null)
this.Labels = (from item in data.Labels select item).ToDictionary(t => t.Item1, t => t.Item2);
if (data.NamespaceLayer != null)
this.NamespaceLayer = (from item in data.NamespaceLayer select item).ToDictionary(t => t.Item1, t => t.Item2);
if (data.NamespaceLabels != null)
this.NamespaceLabels = (from item in data.NamespaceLabels select item).ToDictionary(t => t.Item1, t => t.Item2);
if (data.JumpPointerCache != null)
this.JumpPointerCache = (from item in data.JumpPointerCache select item).ToDictionary(t => t.Item1, t => t.Item2);
}
public RScriptSentence CurrentSentence => Sentences[CurrentRuntimePointer];
private void DoDefineVariable(ExpressionParser parser, RScriptSentence sentence)
{
// 定义变量
var varTypeName = sentence.info[0];
var varName = sentence.info[1];
Type varType;
object varDefaultValue;
{
if (varTypeName == "string")
{
varType = typeof(string);
varDefaultValue = string.Empty;
}
else if (varTypeName == "int")
{
varType = typeof(int);
varDefaultValue = 0;
}
else if (varTypeName == "double")
{
varType = typeof(double);
varDefaultValue = 0.0;
}
else if (varTypeName == "float")
{
varType = typeof(float);
varDefaultValue = 0.0f;
}
else if (varTypeName == "bool")
{
varType = typeof(bool);
varDefaultValue = false;
}
else if (varTypeName == "var")
{
varType = typeof(object);
varDefaultValue = new object();
}
else
{
throw new RScriptException($"Unsupported variable type '{varTypeName}'.", CurrentRuntimePointer);
}
}
if (CurrentLocalSpaceVariableNames.Peek().Contains(varName) == false)
{
Variables.Add(varName, new() { type = varType, data = varDefaultValue });
parser.context.Variables[varName] = varDefaultValue;
CurrentLocalSpaceVariableNames.Peek().Add(varName);
}
else
{
throw new RScriptException($"Variable '{varName}' already defined on this namespace.", CurrentRuntimePointer);
}
}
private void DoEnterNamespace(ExpressionParser parser)
{
// 准备记录当前命名空间中定义的变量, 清空上层命名空间的变量
CurrentLocalSpaceVariableNames.Push(new());
// 更新变量值
foreach (var (varName, varValue) in parser.context.Variables)
{
Variables.SetValue(varName, varValue);
}
// 压栈
RuntimePointerStack.Push(CurrentRuntimePointer);
}
private void DoExitNamespace(ExpressionParser parser)
{
// 移除当前命名空间的变量
foreach (var local in CurrentLocalSpaceVariableNames.Peek())
{
Variables.Remove(local);
parser.context.Variables.Remove(local);
}
// 还原上层命名空间的变量
foreach (var local in CurrentLocalSpaceVariableNames.Peek())
{
parser.context.Variables[local] = Variables[local].data;
}
CurrentLocalSpaceVariableNames.Pop();
// 弹栈
RuntimePointerStack.Pop();
}
private void DoJumpRuntimePointer(ExpressionParser parser, int target)
{
bool isForwardMove = target > CurrentRuntimePointer;
int step = isForwardMove ? 1 : -1;
for (; CurrentRuntimePointer != target; CurrentRuntimePointer += step)
{
if (CurrentSentence.mode == RScriptSentence.Mode.ExitNamespace)
{
if (isForwardMove)
DoExitNamespace(parser);
else
DoEnterNamespace(parser);
}
else if (CurrentSentence.mode == RScriptSentence.Mode.EnterNamespace)
{
if (isForwardMove)
DoEnterNamespace(parser);
else
DoExitNamespace(parser);
}
}
}
private void DoGoto(ExpressionParser parser, RScriptSentence sentence)
{
// 检查并跳转到指定标签
if (parser.Evaluate<bool>(sentence.info[0]))
{
if (Labels.TryGetValue(sentence.content, out var labelPointer))
{
GotoPointerStack.Push(CurrentRuntimePointer);
DoJumpRuntimePointer(parser, labelPointer);
}
else
{
throw new RScriptException($"Label '{sentence.content}' not found.", CurrentRuntimePointer);
}
}
}
private void DoBreakpoint(ExpressionParser parser, RScriptSentence sentence)
{
// 检查并跳转到当前命名空间的结束位置
if (parser.Evaluate<bool>(sentence.content))
{
if (RuntimePointerStack.Count == 0)
{
CurrentRuntimePointer = Sentences.Length;
}
else if (Namespace.TryGetValue(RuntimePointerStack.Peek(), out var exitPointer))
{
CurrentRuntimePointer = exitPointer;
DoExitNamespace(parser);
}
else
{
throw new NotImplementedException($"No namespace to break.");
}
}
}
private void DoBackpoint(ExpressionParser parser, RScriptSentence sentence)
{
// 检查并跳转到上次跳转的位置
if (parser.Evaluate<bool>(sentence.content))
{
if (GotoPointerStack.Count == 0)
{
throw new NotImplementedException($"No position to back.");
}
else
{
DoJumpRuntimePointer(parser, GotoPointerStack.Pop());
}
}
}
private object RunNextStep(ExpressionParser parser)
internal object RunNextStep(ExpressionParser parser)
{
var sentence = CurrentSentence;
switch (sentence.mode)
try
{
case RScriptSentence.Mode.Expression:
return parser.Evaluate(sentence.content);
case RScriptSentence.Mode.DefineVariable:
return SentenceRunners.TryGetValue(sentence.mode, out var runner) ? runner.Run(parser, sentence, this) : null;
}
catch (RScriptException)
{
DoDefineVariable(parser, sentence);
throw;
}
break;
case RScriptSentence.Mode.EnterNamespace:
catch (Exception ex)
{
DoEnterNamespace(parser);
throw new RScriptRuntimeException($"Runtime error: {ex.Message}", CurrentRuntimePointer, ex);
}
break;
case RScriptSentence.Mode.ExitNamespace:
}
internal IEnumerator RunNextStepAsync(ExpressionParser parser)
{
DoExitNamespace(parser);
}
break;
case RScriptSentence.Mode.Goto:
{
DoGoto(parser, sentence);
}
break;
case RScriptSentence.Mode.Breakpoint:
{
DoBreakpoint(parser, sentence);
}
break;
case RScriptSentence.Mode.Backpoint:
{
DoBackpoint(parser, sentence);
}
break;
default:
// Do nothing
break;
}
return null;
var sentence = CurrentSentence;
if (SentenceRunners.TryGetValue(sentence.mode, out var runner))
yield return runner.RunAsync(parser, sentence, this);
}
private readonly Stack<int> RuntimePointerStack = new();
private readonly Stack<int> GotoPointerStack = new();
private int CurrentRuntimePointer = 0;
private readonly Stack<HashSet<string>> CurrentLocalSpaceVariableNames = new();
internal readonly Stack<int> RuntimePointerStack = new();
internal readonly Stack<int> GotoPointerStack = new();
internal readonly Dictionary<Tuple<int, int>, Tuple<int, int>> JumpPointerCache = new();
public int CurrentRuntimePointer { get; internal set; } = 0;
internal readonly Stack<HashSet<string>> CurrentLocalSpaceVariableNames = new();
public Dictionary<string, RScriptVariableEntry> GetCurrentVariables()
{
@@ -353,18 +306,42 @@ namespace Convention.RScript
return result;
}
public void Run(ExpressionParser parser)
private void BeforeRun(ExpressionParser parser)
{
CurrentLocalSpaceVariableNames.Clear();
RuntimePointerStack.Clear();
GotoPointerStack.Clear();
CurrentLocalSpaceVariableNames.Clear();
CurrentLocalSpaceVariableNames.Push(new());
for (CurrentRuntimePointer = 0; CurrentRuntimePointer < Sentences.Length; CurrentRuntimePointer++)
JumpPointerCache.Clear();
parser.context.Imports.AddType(typeof(Variable.RScriptVariableGenerater));
foreach (var staticType in Import)
{
RunNextStep(parser);
parser.context.Imports.AddType(staticType);
}
// 更新上下文变量
foreach (var (name, varObject) in Variables)
{
parser.context.Variables[name] = varObject.data;
}
}
private void ResetAndSureRunAgain(ExpressionParser parser)
{
CurrentLocalSpaceVariableNames.Clear();
RuntimePointerStack.Clear();
GotoPointerStack.Clear();
CurrentLocalSpaceVariableNames.Clear();
CurrentLocalSpaceVariableNames.Push(new());
JumpPointerCache.Clear();
parser.context.Variables.Clear();
foreach (var (name, varObject) in Variables)
{
parser.context.Variables[name] = varObject.data;
}
}
private void AfterRun(ExpressionParser parser)
{
foreach (var (varName, varValue) in parser.context.Variables)
{
if (Variables.ContainsKey(varName))
@@ -372,28 +349,76 @@ namespace Convention.RScript
}
}
public IEnumerator RunAsync(ExpressionParser parser)
public void Run(ExpressionParser parser)
{
CurrentLocalSpaceVariableNames.Clear();
RuntimePointerStack.Clear();
GotoPointerStack.Clear();
CurrentLocalSpaceVariableNames.Clear();
CurrentLocalSpaceVariableNames.Push(new());
BeforeRun(parser);
Stack<IEnumerator> buffer = new();
for (CurrentRuntimePointer = 0; CurrentRuntimePointer < Sentences.Length; CurrentRuntimePointer++)
{
var ret = RunNextStep(parser);
if (ret is IEnumerator ir)
RunNextStep(parser);
}
AfterRun(parser);
}
public IEnumerator RunAsync(ExpressionParser parser)
{
yield return ir;
}
yield return null;
}
// 更新上下文变量
foreach (var (varName, varValue) in parser.context.Variables)
BeforeRun(parser);
for (CurrentRuntimePointer = 0; CurrentRuntimePointer < Sentences.Length; CurrentRuntimePointer++)
{
if (Variables.ContainsKey(varName))
Variables.SetValue(varName, varValue);
}
yield return RunNextStepAsync(parser);
}
AfterRun(parser);
}
public void ReRun(ExpressionParser parser)
{
ResetAndSureRunAgain(parser);
for (CurrentRuntimePointer = 0; CurrentRuntimePointer < Sentences.Length; CurrentRuntimePointer++)
{
RunNextStep(parser);
}
AfterRun(parser);
}
public IEnumerator ReRunAsync(ExpressionParser parser)
{
ResetAndSureRunAgain(parser);
for (CurrentRuntimePointer = 0; CurrentRuntimePointer < Sentences.Length; CurrentRuntimePointer++)
{
yield return RunNextStepAsync(parser);
}
AfterRun(parser);
}
public SerializableClass Compile(ExpressionParser parser)
{
BeforeRun(parser);
//foreach (var item in Sentences)
//{
// if (SentenceRunners.TryGetValue(item.mode, out var runner))
// runner.Compile(parser, item, this);
//}
return new SerializableClass()
{
//CompileParser = parser.Serialize(),
Labels = (from item in Labels select Tuple.Create(item.Key, item.Value)).ToArray(),
NamespaceLayer = (from item in NamespaceLayer select Tuple.Create(item.Key, item.Value)).ToArray(),
NamespaceLabels = (from item in NamespaceLabels select Tuple.Create(item.Key, item.Value)).ToArray(),
Sentences = Sentences,
JumpPointerCache = (from item in JumpPointerCache select Tuple.Create(item.Key, item.Value)).ToArray(),
};
}
public SerializableClass CompileFromCurrent(ExpressionParser parser)
{
return new SerializableClass()
{
//CompileParser = parser.Serialize(),
Labels = (from item in Labels select Tuple.Create(item.Key, item.Value)).ToArray(),
NamespaceLayer = (from item in NamespaceLayer select Tuple.Create(item.Key, item.Value)).ToArray(),
NamespaceLabels = (from item in NamespaceLabels select Tuple.Create(item.Key, item.Value)).ToArray(),
Sentences = Sentences,
JumpPointerCache = (from item in JumpPointerCache select Tuple.Create(item.Key, item.Value)).ToArray(),
};
}
}
}

View File

@@ -6,23 +6,33 @@ using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using static Convention.RScript.RScriptContext;
namespace Convention.RScript
{
public class RScriptEngine
public interface IRScriptEngine
{
IBasicRScriptContext context { get; }
Dictionary<string, RScriptVariableEntry> Run(string script, RScriptImportClass import = null, RScriptVariables variables = null);
IEnumerator RunAsync(string script, RScriptImportClass import = null, RScriptVariables variables = null);
SerializableClass Compile(string script, RScriptImportClass import = null, RScriptVariables variables = null);
SerializableClass GetCompileResultFromCurrent();
Dictionary<string, RScriptVariableEntry> Run(SerializableClass data, RScriptImportClass import = null, RScriptVariables variables = null);
IEnumerator RunAsync(SerializableClass data, RScriptImportClass import = null, RScriptVariables variables = null);
}
public sealed class RScriptEngine : IRScriptEngine
{
private ExpressionParser parser;
private RScriptContext context;
public IBasicRScriptContext context { get; private set; }
private IEnumerable<string> SplitScript(string script)
{
StringBuilder builder = new();
List<string> statements = new();
for (int i = 0, e = script.Length; i < e; i++)
{
char c = script[i];
if (c == ';')
void PushBuilder()
{
if (builder.Length > 0)
{
@@ -30,21 +40,25 @@ namespace Convention.RScript
builder.Clear();
}
}
var lines = script.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None);
for (int lineIndex = 0; lineIndex < lines.Length; lineIndex++)
{
string line = lines[lineIndex];
for (int i = 0, e = line.Length; i < e; i++)
{
char c = line[i];
if (c == ';')
{
PushBuilder();
}
else if (c == '/' && i + 1 < e)
{
// Skip single-line comment
if (script[i + 1] == '/')
if (line[i + 1] == '/')
{
while (i < script.Length && script[i] != '\n')
i++;
}
// Skip multi-line comment
else if (script[i + 1] == '*')
{
i += 2;
while (i + 1 < script.Length && !(script[i] == '*' && script[i + 1] == '/'))
i++;
i++;
PushBuilder();
break;
}
else
{
@@ -53,59 +67,74 @@ namespace Convention.RScript
}
else if (c == '#')
{
// Skip single-line comment
while (i < script.Length && script[i] != '\n')
i++;
PushBuilder();
break;
}
else if (c == '\"')
{
builder.Append(c);
for (i++; i < e; i++)
{
builder.Append(script[i]);
if (script[i] == '\"')
builder.Append(line[i]);
if (line[i] == '\"')
{
break;
}
else if (script[i] == '\\')
else if (line[i] == '\\')
{
i++;
if (i < e)
builder.Append(script[i]);
builder.Append(line[i]);
else
throw new RScriptException("Invalid escape sequence in string literal", -1);
throw new RScriptCompileException("Invalid escape sequence in string literal", lineIndex, i);
}
}
}
else if (c == '{' || c == '}')
{
// Treat braces as statement separators
if (builder.Length > 0)
{
statements.Add(builder.ToString().Trim());
builder.Clear();
}
PushBuilder();
statements.Add(c.ToString());
}
else if (string.Compare("namespace", 0, line, i, "namespace".Length) == 0)
{
Regex regex = new(@"^\s*namespace\s*\([a-zA-Z_][a-zA-Z0-9_]*\)");
var match = regex.Match(line);
if (match.Success)
{
builder.Append(match.Value);
PushBuilder();
i += match.Length;
}
else
{
throw new RScriptCompileException("Invalid namespace declaration", lineIndex, i);
}
// 前面的操作中已经完成位移, 此处是抵消循环中的i++
i -= 1;
}
else
{
builder.Append(c);
}
}
if (builder.Length > 0)
{
statements.Add(builder.ToString().Trim());
builder.Clear();
}
PushBuilder();
return statements.Where(s => !string.IsNullOrWhiteSpace(s));
}
private IBasicRScriptContext CreateContext(string[] statements, RScriptImportClass import = null, RScriptVariables variables = null)
{
return new RScriptContext(statements, import, variables);
}
private IBasicRScriptContext CreateContext(SerializableClass data, RScriptImportClass import = null, RScriptVariables variables = null)
{
return new RScriptContext(data, import, variables);
}
public Dictionary<string, RScriptVariableEntry> Run(string script, RScriptImportClass import = null, RScriptVariables variables = null)
{
parser = new(new());
context = new(SplitScript(script).ToArray(), import, variables);
foreach (var type in context.Import)
parser.context.Imports.AddType(type);
context = CreateContext(SplitScript(script).ToArray(), import, variables);
context.Run(parser);
return context.GetCurrentVariables();
}
@@ -113,10 +142,45 @@ namespace Convention.RScript
public IEnumerator RunAsync(string script, RScriptImportClass import = null, RScriptVariables variables = null)
{
parser = new(new());
context = new(SplitScript(script).ToArray(), import, variables);
foreach (var type in context.Import)
parser.context.Imports.AddType(type);
return context.RunAsync(parser);
}
context = CreateContext(SplitScript(script).ToArray(), import, variables);
yield return context.RunAsync(parser);
}
public SerializableClass Compile(string script, RScriptImportClass import = null, RScriptVariables variables = null)
{
parser = new(new());
context = CreateContext(SplitScript(script).ToArray(), import, variables);
return context.Compile(parser);
}
public SerializableClass GetCompileResultFromCurrent()
{
return context.CompileFromCurrent(parser);
}
public Dictionary<string, RScriptVariableEntry> Run(SerializableClass data, RScriptImportClass import = null, RScriptVariables variables = null)
{
parser = new(new());
//parser.Deserialize(data.CompileParser);
context = CreateContext(data, import, variables);
context.Run(parser);
return context.GetCurrentVariables();
}
public IEnumerator RunAsync(SerializableClass data, RScriptImportClass import = null, RScriptVariables variables = null)
{
parser = new(new());
//parser.Deserialize(data.CompileParser);
context = CreateContext(data, import, variables);
yield return context.RunAsync(parser);
}
public Dictionary<string, RScriptVariableEntry> ReRun()
{
context.ReRun(parser);
return context.GetCurrentVariables();
}
public IEnumerator ReRunAsync()
{
yield return context.ReRunAsync(parser);
}
}
}

158
RScriptSerializer.cs Normal file
View File

@@ -0,0 +1,158 @@
using System;
using System.IO;
using static Convention.RScript.RScriptContext;
namespace Convention.RScript
{
public static class RScriptSerializer
{
public static byte[] SerializeClass(SerializableClass data)
{
using (var stream = new MemoryStream())
using (var writer = new BinaryWriter(stream))
{
// 序列化 Sentences 数组
writer.Write(data.Sentences?.Length ?? 0);
if (data.Sentences != null)
{
foreach (var sentence in data.Sentences)
{
writer.Write(sentence.content ?? "");
writer.Write(sentence.info?.Length ?? 0);
if (sentence.info != null)
{
foreach (var info in sentence.info)
{
writer.Write(info ?? "");
}
}
writer.Write((int)sentence.mode);
}
}
// 序列化 Labels 数组
writer.Write(data.Labels?.Length ?? 0);
if (data.Labels != null)
{
foreach (var label in data.Labels)
{
writer.Write(label.Item1 ?? "");
writer.Write(label.Item2);
}
}
// 序列化 NamespaceLayer 数组
writer.Write(data.NamespaceLayer?.Length ?? 0);
if (data.NamespaceLayer != null)
{
foreach (var layer in data.NamespaceLayer)
{
writer.Write(layer.Item1);
writer.Write(layer.Item2);
}
}
// 序列化 NamespaceLabels 数组
writer.Write(data.NamespaceLabels?.Length ?? 0);
if (data.NamespaceLabels != null)
{
foreach (var nsLabel in data.NamespaceLabels)
{
writer.Write(nsLabel.Item1 ?? "");
writer.Write(nsLabel.Item2);
}
}
// 序列化 JumpPointerCache 数组
writer.Write(data.JumpPointerCache?.Length ?? 0);
if (data.JumpPointerCache != null)
{
foreach (var jpItem in data.JumpPointerCache)
{
writer.Write(jpItem.Item1.Item1);
writer.Write(jpItem.Item1.Item2);
writer.Write(jpItem.Item2.Item1);
writer.Write(jpItem.Item2.Item2);
}
}
return stream.ToArray();
}
}
public static SerializableClass DeserializeClass(byte[] data)
{
using (var stream = new MemoryStream(data))
using (var reader = new BinaryReader(stream))
{
var result = new SerializableClass();
// 反序列化 Sentences 数组
int sentencesLength = reader.ReadInt32();
result.Sentences = new RScriptSentence[sentencesLength];
for (int i = 0; i < sentencesLength; i++)
{
var sentence = new RScriptSentence();
sentence.content = reader.ReadString();
int infoLength = reader.ReadInt32();
if (infoLength > 0)
{
sentence.info = new string[infoLength];
for (int j = 0; j < infoLength; j++)
{
sentence.info[j] = reader.ReadString();
}
}
sentence.mode = (RScriptSentence.Mode)reader.ReadInt32();
result.Sentences[i] = sentence;
}
// 反序列化 Labels 数组
int labelsLength = reader.ReadInt32();
result.Labels = new Tuple<string, int>[labelsLength];
for (int i = 0; i < labelsLength; i++)
{
string item1 = reader.ReadString();
int item2 = reader.ReadInt32();
result.Labels[i] = Tuple.Create(item1, item2);
}
// 反序列化 NamespaceLayer 数组
int namespaceLayerLength = reader.ReadInt32();
result.NamespaceLayer = new Tuple<int, int>[namespaceLayerLength];
for (int i = 0; i < namespaceLayerLength; i++)
{
int item1 = reader.ReadInt32();
int item2 = reader.ReadInt32();
result.NamespaceLayer[i] = Tuple.Create(item1, item2);
}
// 反序列化 NamespaceLabels 数组
int namespaceLabelsLength = reader.ReadInt32();
result.NamespaceLabels = new Tuple<string, int>[namespaceLabelsLength];
for (int i = 0; i < namespaceLabelsLength; i++)
{
string item1 = reader.ReadString();
int item2 = reader.ReadInt32();
result.NamespaceLabels[i] = Tuple.Create(item1, item2);
}
// 反序列化 JumpPointerCache 数组
int jumpPointerCacheLength = reader.ReadInt32();
result.JumpPointerCache = new Tuple<Tuple<int, int>, Tuple<int, int>>[jumpPointerCacheLength];
for (int i = 0; i < jumpPointerCacheLength; i++)
{
int x = reader.ReadInt32();
int y = reader.ReadInt32();
int z = reader.ReadInt32();
int w = reader.ReadInt32();
result.JumpPointerCache[i] = Tuple.Create(Tuple.Create(x, y), Tuple.Create(z, w));
}
return result;
}
}
}
}