解离出Runner

This commit is contained in:
2025-10-16 15:20:53 +08:00
parent e2ab2a1077
commit 15bdb6f8db
9 changed files with 301 additions and 237 deletions

View File

@@ -0,0 +1,26 @@
using Convention.RScript.Parser;
using System.Diagnostics.CodeAnalysis;
namespace Convention.RScript.Runner
{
public class BackpointRunner : JumpRuntimePointerRunner
{
[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;
}
}
}

View File

@@ -0,0 +1,32 @@
using Convention.RScript.Parser;
using System.Diagnostics.CodeAnalysis;
namespace Convention.RScript
{
public class BreakpointRunner : IRSentenceRunner
{
[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;
//DoExitNamespace(parser);
context.SentenceRunners[RScriptSentence.Mode.ExitNamespace].Run(parser, context.CurrentSentence, context);
}
else
{
throw new RScriptRuntimeException($"No namespace to break.", context.CurrentRuntimePointer);
}
}
return null;
}
}
}

View File

@@ -0,0 +1,67 @@
using Convention.RScript.Parser;
using System;
using System.Diagnostics.CodeAnalysis;
namespace Convention.RScript.Runner
{
public class DefineVariableRunner : IRSentenceRunner
{
[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;
}
else if (varTypeName == "int")
{
varType = typeof(int);
varDefaultValue = varInitExpression == null ? 0 : parser.Evaluate<int>(varInitExpression);
}
else if (varTypeName == "double")
{
varType = typeof(double);
varDefaultValue = varInitExpression == null ? 0.0 : parser.Evaluate<double>(varInitExpression);
}
else if (varTypeName == "float")
{
varType = typeof(float);
varDefaultValue = varInitExpression == null ? 0.0f : parser.Evaluate<float>(varInitExpression);
}
else if (varTypeName == "bool")
{
varType = typeof(bool);
varDefaultValue = varInitExpression == null ? false : parser.Evaluate<bool>(varInitExpression);
}
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;
}
}
}

View File

@@ -0,0 +1,23 @@
using Convention.RScript.Parser;
using System.Diagnostics.CodeAnalysis;
namespace Convention.RScript.Runner
{
public class EnterNamespaceRunner : IRSentenceRunner
{
[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;
}
}
}

View File

@@ -0,0 +1,28 @@
using Convention.RScript.Parser;
using System.Diagnostics.CodeAnalysis;
namespace Convention.RScript.Runner
{
public class ExitNamespaceRunner : IRSentenceRunner
{
[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())
{
parser.context.Variables[local] = context.Variables[local].data;
}
context.CurrentLocalSpaceVariableNames.Pop();
// 弹栈
context.RuntimePointerStack.Pop();
return null;
}
}
}

View File

@@ -0,0 +1,14 @@
using Convention.RScript.Parser;
using System.Diagnostics.CodeAnalysis;
namespace Convention.RScript.Runner
{
public class ExpressionRunner : IRSentenceRunner
{
[return: MaybeNull]
public object Run(ExpressionParser parser, RScriptSentence sentence, RScriptContext context)
{
return parser.Evaluate(sentence.content);
}
}
}

47
DoRunner/GoToRunner.cs Normal file
View File

@@ -0,0 +1,47 @@
using Convention.RScript.Parser;
using System.Diagnostics.CodeAnalysis;
namespace Convention.RScript.Runner
{
public class GoToRunner : JumpRuntimePointerRunner
{
[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;
}
}
}

View File

@@ -0,0 +1,38 @@
using Convention.RScript.Parser;
using System.Diagnostics.CodeAnalysis;
namespace Convention.RScript.Runner
{
public abstract class JumpRuntimePointerRunner : IRSentenceRunner
{
protected void DoJumpRuntimePointer(ExpressionParser parser, int target, RScriptContext context)
{
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)
//DoExitNamespace(parser);
context.SentenceRunners[RScriptSentence.Mode.ExitNamespace].Run(parser, context.CurrentSentence, context);
else
//DoEnterNamespace(parser);
context.SentenceRunners[RScriptSentence.Mode.EnterNamespace].Run(parser, context.CurrentSentence, context);
}
else if (context.CurrentSentence.mode == RScriptSentence.Mode.EnterNamespace)
{
if (isForwardMove)
//DoEnterNamespace(parser);
context.SentenceRunners[RScriptSentence.Mode.EnterNamespace].Run(parser, context.CurrentSentence, context);
else
//DoExitNamespace(parser);
context.SentenceRunners[RScriptSentence.Mode.ExitNamespace].Run(parser, context.CurrentSentence, context);
}
}
}
[return: MaybeNull]
public abstract object Run(ExpressionParser parser, RScriptSentence sentence, RScriptContext context);
}
}

View File

@@ -1,8 +1,10 @@
using Convention.RScript.Matcher; using Convention.RScript.Matcher;
using Convention.RScript.Parser; using Convention.RScript.Parser;
using Convention.RScript.Runner;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
namespace Convention.RScript namespace Convention.RScript
@@ -69,14 +71,19 @@ namespace Convention.RScript
bool Match(string expression, ref RScriptSentence sentence); bool Match(string expression, ref RScriptSentence sentence);
} }
public interface IRSentenceRunner
{
[return: MaybeNull] object Run(ExpressionParser parser, RScriptSentence sentence, RScriptContext context);
}
public partial class RScriptContext public partial class RScriptContext
{ {
public readonly RScriptImportClass Import; public readonly RScriptImportClass Import;
public readonly RScriptVariables Variables; public readonly RScriptVariables Variables;
private readonly RScriptSentence[] Sentences; internal readonly RScriptSentence[] Sentences;
private readonly Dictionary<string, int> Labels = new(); internal readonly Dictionary<string, int> Labels = new();
private readonly Dictionary<int, int> NamespaceLayer = new(); internal readonly Dictionary<int, int> NamespaceLayer = new();
private readonly Dictionary<string, int> NamespaceLabels = new(); internal readonly Dictionary<string, int> NamespaceLabels = new();
public List<IRSentenceMatcher> SentenceParser = new() public List<IRSentenceMatcher> SentenceParser = new()
{ {
@@ -161,241 +168,24 @@ namespace Convention.RScript
public RScriptSentence CurrentSentence => Sentences[CurrentRuntimePointer]; public RScriptSentence CurrentSentence => Sentences[CurrentRuntimePointer];
private void DoDefineVariable(ExpressionParser parser, RScriptSentence sentence) public Dictionary<RScriptSentence.Mode, IRSentenceRunner> SentenceRunners = new()
{ {
// 定义变量 { RScriptSentence.Mode.DefineVariable, new DefineVariableRunner() },
var varTypeName = sentence.info[0]; { RScriptSentence.Mode.EnterNamespace, new EnterNamespaceRunner() },
var varName = sentence.info[1]; { RScriptSentence.Mode.ExitNamespace, new ExitNamespaceRunner() },
var varInitExpression = sentence.info[2]; { RScriptSentence.Mode.Goto, new GoToRunner() },
Type varType; { RScriptSentence.Mode.Breakpoint, new BreakpointRunner() },
object varDefaultValue; { RScriptSentence.Mode.Backpoint, new BackpointRunner() },
{ { RScriptSentence.Mode.Expression, new ExpressionRunner() },
if (varTypeName == "string") };
{
varType = typeof(string);
varDefaultValue = varInitExpression == null ? string.Empty : varInitExpression;
}
else if (varTypeName == "int")
{
varType = typeof(int);
varDefaultValue = varInitExpression == null ? 0 : parser.Evaluate<int>(varInitExpression);
}
else if (varTypeName == "double")
{
varType = typeof(double);
varDefaultValue = varInitExpression == null ? 0.0 : parser.Evaluate<double>(varInitExpression);
}
else if (varTypeName == "float")
{
varType = typeof(float);
varDefaultValue = varInitExpression == null ? 0.0f : parser.Evaluate<float>(varInitExpression);
}
else if (varTypeName == "bool")
{
varType = typeof(bool);
varDefaultValue = varInitExpression == null ? false : parser.Evaluate<bool>(varInitExpression);
}
else if (varTypeName == "var")
{
varType = typeof(object);
varDefaultValue = varInitExpression == null ? new object() : parser.Evaluate(varInitExpression);
}
else
{
throw new RScriptRuntimeException($"Unsupported variable type '{varTypeName}'.", CurrentRuntimePointer);
}
}
if (CurrentLocalSpaceVariableNames.Peek().Contains(varName) == false)
{
Variables.Add(varName, new(varType, varDefaultValue));
parser.context.Variables[varName] = varDefaultValue;
CurrentLocalSpaceVariableNames.Peek().Add(varName);
}
else
{
throw new RScriptRuntimeException($"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) internal object RunNextStep(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 if (NamespaceLabels.TryGetValue(sentence.content, out labelPointer))
{
int current = CurrentRuntimePointer;
DoEnterNamespace(parser);
CurrentRuntimePointer = labelPointer;
for (int e = NamespaceLayer[NamespaceLabels[sentence.content]]; ;)
{
RunNextStep(parser);
if (CurrentRuntimePointer >= Sentences.Length)
break ;
else if (CurrentRuntimePointer == e)
break;
else
CurrentRuntimePointer++;
}
DoExitNamespace(parser);
CurrentRuntimePointer = current;
}
else
{
throw new RScriptRuntimeException($"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 (NamespaceLayer.TryGetValue(RuntimePointerStack.Peek(), out var exitPointer))
{
CurrentRuntimePointer = exitPointer;
DoExitNamespace(parser);
}
else
{
throw new RScriptRuntimeException($"No namespace to break.", CurrentRuntimePointer);
}
}
}
private void DoBackpoint(ExpressionParser parser, RScriptSentence sentence)
{
// 检查并跳转到上次跳转的位置
if (parser.Evaluate<bool>(sentence.content))
{
if (GotoPointerStack.Count == 0)
{
throw new RScriptRuntimeException($"No position to back.", CurrentRuntimePointer);
}
else
{
DoJumpRuntimePointer(parser, GotoPointerStack.Pop());
}
}
}
private void DoEnterNamedSpace(RScriptSentence sentence)
{
CurrentRuntimePointer = NamespaceLayer[NamespaceLabels[sentence.content]];
}
private object RunNextStep(ExpressionParser parser)
{ {
var sentence = CurrentSentence; var sentence = CurrentSentence;
try try
{ {
switch (sentence.mode) return SentenceRunners.TryGetValue(sentence.mode, out var runner) ? runner.Run(parser, sentence, this) : null;
{
case RScriptSentence.Mode.Expression:
return parser.Evaluate(sentence.content);
case RScriptSentence.Mode.DefineVariable:
{
DoDefineVariable(parser, sentence);
}
break;
case RScriptSentence.Mode.EnterNamespace:
{
DoEnterNamespace(parser);
}
break;
case RScriptSentence.Mode.ExitNamespace:
{
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;
case RScriptSentence.Mode.NamedSpace:
{
DoEnterNamedSpace(sentence);
}
break;
default:
// Do nothing
break;
}
} }
catch (RScriptRuntimeException) catch (RScriptRuntimeException)
{ {
@@ -405,13 +195,12 @@ namespace Convention.RScript
{ {
throw new RScriptRuntimeException($"Runtime error: {ex.Message}", CurrentRuntimePointer, ex); throw new RScriptRuntimeException($"Runtime error: {ex.Message}", CurrentRuntimePointer, ex);
} }
return null;
} }
private readonly Stack<int> RuntimePointerStack = new(); internal readonly Stack<int> RuntimePointerStack = new();
private readonly Stack<int> GotoPointerStack = new(); internal readonly Stack<int> GotoPointerStack = new();
private int CurrentRuntimePointer = 0; public int CurrentRuntimePointer { get; internal set; } = 0;
private readonly Stack<HashSet<string>> CurrentLocalSpaceVariableNames = new(); internal readonly Stack<HashSet<string>> CurrentLocalSpaceVariableNames = new();
public Dictionary<string, RScriptVariableEntry> GetCurrentVariables() public Dictionary<string, RScriptVariableEntry> GetCurrentVariables()
{ {