diff --git a/DoRunner/BackpointRunner.cs b/DoRunner/BackpointRunner.cs index aaf9659..5620cdc 100644 --- a/DoRunner/BackpointRunner.cs +++ b/DoRunner/BackpointRunner.cs @@ -1,4 +1,5 @@ using Convention.RScript.Parser; +using System.Collections; using System.Diagnostics.CodeAnalysis; namespace Convention.RScript.Runner @@ -27,5 +28,23 @@ namespace Convention.RScript.Runner } return null; } + + [return: MaybeNull] + public override IEnumerator RunAsync(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); + } + } + yield break; + } } } diff --git a/DoRunner/BreakpointRunner.cs b/DoRunner/BreakpointRunner.cs index fced294..89c88ae 100644 --- a/DoRunner/BreakpointRunner.cs +++ b/DoRunner/BreakpointRunner.cs @@ -1,4 +1,5 @@ using Convention.RScript.Parser; +using System.Collections; using System.Diagnostics.CodeAnalysis; namespace Convention.RScript @@ -23,7 +24,7 @@ namespace Convention.RScript else if (context.NamespaceLayer.TryGetValue(context.RuntimePointerStack.Peek(), out var exitPointer)) { context.CurrentRuntimePointer = exitPointer; - context.SentenceRunners[RScriptSentence.Mode.ExitNamespace].Run(parser, context.CurrentSentence, context); + return context.SentenceRunners[RScriptSentence.Mode.ExitNamespace].Run(parser, context.CurrentSentence, context); } else { @@ -32,5 +33,27 @@ namespace Convention.RScript } return null; } + + [return: MaybeNull] + public IEnumerator RunAsync(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; + yield return context.SentenceRunners[RScriptSentence.Mode.ExitNamespace].RunAsync(parser, context.CurrentSentence, context); + } + else + { + throw new RScriptRuntimeException($"No namespace to break.", context.CurrentRuntimePointer); + } + } + } } } diff --git a/DoRunner/DefineVariableRunner.cs b/DoRunner/DefineVariableRunner.cs index 25f740a..7d292d4 100644 --- a/DoRunner/DefineVariableRunner.cs +++ b/DoRunner/DefineVariableRunner.cs @@ -1,5 +1,6 @@ using Convention.RScript.Parser; using System; +using System.Collections; using System.Diagnostics.CodeAnalysis; namespace Convention.RScript.Runner @@ -123,5 +124,63 @@ namespace Convention.RScript.Runner } 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; + } } } diff --git a/DoRunner/EnterNamedSpaceRunner.cs b/DoRunner/EnterNamedSpaceRunner.cs index c0b47ef..47591a4 100644 --- a/DoRunner/EnterNamedSpaceRunner.cs +++ b/DoRunner/EnterNamedSpaceRunner.cs @@ -1,4 +1,5 @@ using Convention.RScript.Parser; +using System.Collections; using System.Diagnostics.CodeAnalysis; namespace Convention.RScript.Runner @@ -16,5 +17,12 @@ namespace Convention.RScript.Runner 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; + } } } diff --git a/DoRunner/EnterNamespaceRunner.cs b/DoRunner/EnterNamespaceRunner.cs index 36fdb38..50cbf52 100644 --- a/DoRunner/EnterNamespaceRunner.cs +++ b/DoRunner/EnterNamespaceRunner.cs @@ -1,4 +1,5 @@ using Convention.RScript.Parser; +using System.Collections; using System.Diagnostics.CodeAnalysis; namespace Convention.RScript.Runner @@ -24,5 +25,20 @@ namespace Convention.RScript.Runner 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; + } } } diff --git a/DoRunner/ExitNamespaceRunner.cs b/DoRunner/ExitNamespaceRunner.cs index bb1e3ec..e158397 100644 --- a/DoRunner/ExitNamespaceRunner.cs +++ b/DoRunner/ExitNamespaceRunner.cs @@ -1,4 +1,5 @@ using Convention.RScript.Parser; +using System.Collections; using System.Diagnostics.CodeAnalysis; namespace Convention.RScript.Runner @@ -36,5 +37,32 @@ namespace Convention.RScript.Runner 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; + } } } diff --git a/DoRunner/ExpressionRunner.cs b/DoRunner/ExpressionRunner.cs index de96c27..b96c566 100644 --- a/DoRunner/ExpressionRunner.cs +++ b/DoRunner/ExpressionRunner.cs @@ -1,4 +1,5 @@ using Convention.RScript.Parser; +using System.Collections; using System.Diagnostics.CodeAnalysis; namespace Convention.RScript.Runner @@ -15,5 +16,14 @@ namespace Convention.RScript.Runner { 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; + } } } diff --git a/DoRunner/GoToRunner.cs b/DoRunner/GoToRunner.cs index 1d50d29..9cc6fb2 100644 --- a/DoRunner/GoToRunner.cs +++ b/DoRunner/GoToRunner.cs @@ -1,4 +1,5 @@ using Convention.RScript.Parser; +using System.Collections; using System.Diagnostics.CodeAnalysis; namespace Convention.RScript.Runner @@ -48,5 +49,43 @@ namespace Convention.RScript.Runner } return null; } + + [return: MaybeNull] + public override IEnumerator RunAsync(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]]; ;) + { + 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); + } + } + } } } diff --git a/DoRunner/JumpRuntimePointerRunner.cs b/DoRunner/JumpRuntimePointerRunner.cs index 53891ce..0586195 100644 --- a/DoRunner/JumpRuntimePointerRunner.cs +++ b/DoRunner/JumpRuntimePointerRunner.cs @@ -1,5 +1,6 @@ using Convention.RScript.Parser; using System; +using System.Collections; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; @@ -72,5 +73,7 @@ namespace Convention.RScript.Runner 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); } } diff --git a/RScriptContext.cs b/RScriptContext.cs index d881fc3..aeb97a2 100644 --- a/RScriptContext.cs +++ b/RScriptContext.cs @@ -77,6 +77,7 @@ namespace Convention.RScript public interface IRSentenceRunner { [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); } @@ -266,18 +267,8 @@ namespace Convention.RScript public RScriptSentence CurrentSentence => Sentences[CurrentRuntimePointer]; - public int StepCount { get; private set; } - -#if DEBUG - public List StepStack = new(); -#endif - internal object RunNextStep(ExpressionParser parser) { - StepCount++; -#if DEBUG - StepStack.Add(CurrentSentence); -#endif var sentence = CurrentSentence; try { @@ -292,6 +283,12 @@ namespace Convention.RScript throw new RScriptRuntimeException($"Runtime error: {ex.Message}", CurrentRuntimePointer, ex); } } + internal IEnumerator RunNextStepAsync(ExpressionParser parser) + { + var sentence = CurrentSentence; + if (SentenceRunners.TryGetValue(sentence.mode, out var runner)) + yield return runner.RunAsync(parser, sentence, this); + } internal readonly Stack RuntimePointerStack = new(); internal readonly Stack GotoPointerStack = new(); @@ -311,7 +308,6 @@ namespace Convention.RScript private void BeforeRun(ExpressionParser parser) { - StepCount = 0; CurrentLocalSpaceVariableNames.Clear(); RuntimePointerStack.Clear(); GotoPointerStack.Clear(); @@ -331,13 +327,13 @@ namespace Convention.RScript private void ResetAndSureRunAgain(ExpressionParser parser) { - StepCount = 0; 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; @@ -356,6 +352,7 @@ namespace Convention.RScript public void Run(ExpressionParser parser) { BeforeRun(parser); + Stack buffer = new(); for (CurrentRuntimePointer = 0; CurrentRuntimePointer < Sentences.Length; CurrentRuntimePointer++) { RunNextStep(parser); @@ -368,12 +365,7 @@ namespace Convention.RScript BeforeRun(parser); for (CurrentRuntimePointer = 0; CurrentRuntimePointer < Sentences.Length; CurrentRuntimePointer++) { - var ret = RunNextStep(parser); - if (ret is IEnumerator ir) - { - yield return ir; - } - yield return null; + yield return RunNextStepAsync(parser); } AfterRun(parser); } @@ -393,12 +385,7 @@ namespace Convention.RScript ResetAndSureRunAgain(parser); for (CurrentRuntimePointer = 0; CurrentRuntimePointer < Sentences.Length; CurrentRuntimePointer++) { - var ret = RunNextStep(parser); - if (ret is IEnumerator ir) - { - yield return ir; - } - yield return null; + yield return RunNextStepAsync(parser); } AfterRun(parser); } diff --git a/RScriptEngine.cs b/RScriptEngine.cs index a4a1a3f..844c280 100644 --- a/RScriptEngine.cs +++ b/RScriptEngine.cs @@ -143,7 +143,7 @@ namespace Convention.RScript { parser = new(new()); context = CreateContext(SplitScript(script).ToArray(), import, variables); - return context.RunAsync(parser); + yield return context.RunAsync(parser); } public SerializableClass Compile(string script, RScriptImportClass import = null, RScriptVariables variables = null) { @@ -179,7 +179,7 @@ namespace Convention.RScript } public IEnumerator ReRunAsync() { - return context.ReRunAsync(parser); + yield return context.ReRunAsync(parser); } }