diff --git a/DoRunner/BackpointRunner.cs b/DoRunner/BackpointRunner.cs new file mode 100644 index 0000000..e99efd7 --- /dev/null +++ b/DoRunner/BackpointRunner.cs @@ -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(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; + } + } +} diff --git a/DoRunner/BreakpointRunner.cs b/DoRunner/BreakpointRunner.cs new file mode 100644 index 0000000..a963f38 --- /dev/null +++ b/DoRunner/BreakpointRunner.cs @@ -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(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; + } + } +} diff --git a/DoRunner/DefineVariableRunner.cs b/DoRunner/DefineVariableRunner.cs new file mode 100644 index 0000000..4df3c8e --- /dev/null +++ b/DoRunner/DefineVariableRunner.cs @@ -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(varInitExpression); + } + else if (varTypeName == "double") + { + varType = typeof(double); + varDefaultValue = varInitExpression == null ? 0.0 : parser.Evaluate(varInitExpression); + } + else if (varTypeName == "float") + { + varType = typeof(float); + varDefaultValue = varInitExpression == null ? 0.0f : parser.Evaluate(varInitExpression); + } + else if (varTypeName == "bool") + { + varType = typeof(bool); + varDefaultValue = varInitExpression == null ? false : parser.Evaluate(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; + } + } +} diff --git a/DoRunner/EnterNamespaceRunner.cs b/DoRunner/EnterNamespaceRunner.cs new file mode 100644 index 0000000..b6a3839 --- /dev/null +++ b/DoRunner/EnterNamespaceRunner.cs @@ -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; + } + } +} diff --git a/DoRunner/ExitNamespaceRunner.cs b/DoRunner/ExitNamespaceRunner.cs new file mode 100644 index 0000000..1a8b842 --- /dev/null +++ b/DoRunner/ExitNamespaceRunner.cs @@ -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; + } + } +} diff --git a/DoRunner/ExpressionRunner.cs b/DoRunner/ExpressionRunner.cs new file mode 100644 index 0000000..380e895 --- /dev/null +++ b/DoRunner/ExpressionRunner.cs @@ -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); + } + } +} diff --git a/DoRunner/GoToRunner.cs b/DoRunner/GoToRunner.cs new file mode 100644 index 0000000..b1d84d5 --- /dev/null +++ b/DoRunner/GoToRunner.cs @@ -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(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; + } + } +} diff --git a/DoRunner/JumpRuntimePointerRunner.cs b/DoRunner/JumpRuntimePointerRunner.cs new file mode 100644 index 0000000..8dd55a3 --- /dev/null +++ b/DoRunner/JumpRuntimePointerRunner.cs @@ -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); + } +} diff --git a/RScriptContext.cs b/RScriptContext.cs index fe0b46d..5c520e4 100644 --- a/RScriptContext.cs +++ b/RScriptContext.cs @@ -1,8 +1,10 @@ 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; namespace Convention.RScript @@ -69,14 +71,19 @@ namespace Convention.RScript 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 readonly RScriptImportClass Import; public readonly RScriptVariables Variables; - private readonly RScriptSentence[] Sentences; - private readonly Dictionary Labels = new(); - private readonly Dictionary NamespaceLayer = new(); - private readonly Dictionary NamespaceLabels = new(); + internal readonly RScriptSentence[] Sentences; + internal readonly Dictionary Labels = new(); + internal readonly Dictionary NamespaceLayer = new(); + internal readonly Dictionary NamespaceLabels = new(); public List SentenceParser = new() { @@ -161,241 +168,24 @@ namespace Convention.RScript public RScriptSentence CurrentSentence => Sentences[CurrentRuntimePointer]; - private void DoDefineVariable(ExpressionParser parser, RScriptSentence sentence) + public Dictionary SentenceRunners = new() { - // 定义变量 - 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(varInitExpression); - } - else if (varTypeName == "double") - { - varType = typeof(double); - varDefaultValue = varInitExpression == null ? 0.0 : parser.Evaluate(varInitExpression); - } - else if (varTypeName == "float") - { - varType = typeof(float); - varDefaultValue = varInitExpression == null ? 0.0f : parser.Evaluate(varInitExpression); - } - else if (varTypeName == "bool") - { - varType = typeof(bool); - varDefaultValue = varInitExpression == null ? false : parser.Evaluate(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); - } - } + { 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() }, + }; - 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(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(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(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) + internal object RunNextStep(ExpressionParser parser) { var sentence = CurrentSentence; try { - switch (sentence.mode) - { - 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; - } + return SentenceRunners.TryGetValue(sentence.mode, out var runner) ? runner.Run(parser, sentence, this) : null; } catch (RScriptRuntimeException) { @@ -405,13 +195,12 @@ namespace Convention.RScript { throw new RScriptRuntimeException($"Runtime error: {ex.Message}", CurrentRuntimePointer, ex); } - return null; } - private readonly Stack RuntimePointerStack = new(); - private readonly Stack GotoPointerStack = new(); - private int CurrentRuntimePointer = 0; - private readonly Stack> CurrentLocalSpaceVariableNames = new(); + internal readonly Stack RuntimePointerStack = new(); + internal readonly Stack GotoPointerStack = new(); + public int CurrentRuntimePointer { get; internal set; } = 0; + internal readonly Stack> CurrentLocalSpaceVariableNames = new(); public Dictionary GetCurrentVariables() {