From d3e21cad156f61ba46a61ec2008231de49ef946b Mon Sep 17 00:00:00 2001 From: ninemine <1371605831@qq.com> Date: Fri, 17 Oct 2025 15:46:44 +0800 Subject: [PATCH] =?UTF-8?q?=E6=AD=A3=E5=9C=A8=E6=96=B0=E5=A2=9E=E7=BC=96?= =?UTF-8?q?=E8=AF=91=E7=BC=93=E5=AD=98=E5=8A=9F=E8=83=BD,=E7=94=A8?= =?UTF-8?q?=E4=BA=8E=E5=8A=A0=E9=80=9F=E4=B8=8E=E5=8A=A0=E5=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DoRunner/BackpointRunner.cs | 5 ++ DoRunner/BreakpointRunner.cs | 6 +- DoRunner/DefineVariableRunner.cs | 60 ++++++++++++++++ DoRunner/EnterNamedSpaceRunner.cs | 5 ++ DoRunner/EnterNamespaceRunner.cs | 5 ++ DoRunner/ExitNamespaceRunner.cs | 5 ++ DoRunner/ExpressionRunner.cs | 5 ++ DoRunner/GoToRunner.cs | 5 ++ DoRunner/JumpRuntimePointerRunner.cs | 1 + Matcher/DefineVariableMatcher.cs | 4 +- Matcher/GotoMatcher.cs | 2 +- Parser/ExpressionParser.cs | 77 +++++++++++++++++++-- PublicTypes/RScriptVariables.cs | 9 ++- RScriptContext.cs | 100 ++++++++++++++++++++++----- RScriptEngine.cs | 52 ++++++++++++-- 15 files changed, 310 insertions(+), 31 deletions(-) diff --git a/DoRunner/BackpointRunner.cs b/DoRunner/BackpointRunner.cs index e99efd7..aaf9659 100644 --- a/DoRunner/BackpointRunner.cs +++ b/DoRunner/BackpointRunner.cs @@ -5,6 +5,11 @@ 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) { diff --git a/DoRunner/BreakpointRunner.cs b/DoRunner/BreakpointRunner.cs index a963f38..fced294 100644 --- a/DoRunner/BreakpointRunner.cs +++ b/DoRunner/BreakpointRunner.cs @@ -5,6 +5,11 @@ namespace Convention.RScript { public class BreakpointRunner : 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) { @@ -18,7 +23,6 @@ namespace Convention.RScript 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 diff --git a/DoRunner/DefineVariableRunner.cs b/DoRunner/DefineVariableRunner.cs index 4df3c8e..54e92a9 100644 --- a/DoRunner/DefineVariableRunner.cs +++ b/DoRunner/DefineVariableRunner.cs @@ -6,6 +6,66 @@ 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(varInitExpression); + varDefaultValue = 0; + } + else if (varTypeName == "double") + { + varType = typeof(double); + if (varInitExpression != null) parser.Compile(varInitExpression); + varDefaultValue = 0.0; + } + else if (varTypeName == "float") + { + varType = typeof(float); + if (varInitExpression != null) parser.Compile(varInitExpression); + varDefaultValue = 0.0f; + } + else if (varTypeName == "bool") + { + varType = typeof(bool); + if (varInitExpression != null) parser.Compile(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) { diff --git a/DoRunner/EnterNamedSpaceRunner.cs b/DoRunner/EnterNamedSpaceRunner.cs index 7b33ddf..c0b47ef 100644 --- a/DoRunner/EnterNamedSpaceRunner.cs +++ b/DoRunner/EnterNamedSpaceRunner.cs @@ -5,6 +5,11 @@ 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) { diff --git a/DoRunner/EnterNamespaceRunner.cs b/DoRunner/EnterNamespaceRunner.cs index b6a3839..36fdb38 100644 --- a/DoRunner/EnterNamespaceRunner.cs +++ b/DoRunner/EnterNamespaceRunner.cs @@ -5,6 +5,11 @@ 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) { diff --git a/DoRunner/ExitNamespaceRunner.cs b/DoRunner/ExitNamespaceRunner.cs index 1a8b842..5303372 100644 --- a/DoRunner/ExitNamespaceRunner.cs +++ b/DoRunner/ExitNamespaceRunner.cs @@ -5,6 +5,11 @@ 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) { diff --git a/DoRunner/ExpressionRunner.cs b/DoRunner/ExpressionRunner.cs index 380e895..de96c27 100644 --- a/DoRunner/ExpressionRunner.cs +++ b/DoRunner/ExpressionRunner.cs @@ -5,6 +5,11 @@ 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) { diff --git a/DoRunner/GoToRunner.cs b/DoRunner/GoToRunner.cs index b1d84d5..1d50d29 100644 --- a/DoRunner/GoToRunner.cs +++ b/DoRunner/GoToRunner.cs @@ -5,6 +5,11 @@ namespace Convention.RScript.Runner { public class GoToRunner : JumpRuntimePointerRunner { + public override void Compile(ExpressionParser parser, RScriptSentence sentence, RScriptContext context) + { + parser.Compile(sentence.info[0]); + } + [return: MaybeNull] public override object Run(ExpressionParser parser, RScriptSentence sentence, RScriptContext context) { diff --git a/DoRunner/JumpRuntimePointerRunner.cs b/DoRunner/JumpRuntimePointerRunner.cs index a05e846..24475f8 100644 --- a/DoRunner/JumpRuntimePointerRunner.cs +++ b/DoRunner/JumpRuntimePointerRunner.cs @@ -59,6 +59,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); } diff --git a/Matcher/DefineVariableMatcher.cs b/Matcher/DefineVariableMatcher.cs index b3cbbe7..ecd1b47 100644 --- a/Matcher/DefineVariableMatcher.cs +++ b/Matcher/DefineVariableMatcher.cs @@ -14,7 +14,7 @@ namespace Convention.RScript.Matcher if (DefineVariableMatch.Success) { sentence.mode = RScriptSentence.Mode.DefineVariable; - sentence.info = new() { DefineVariableMatch.Groups[1].Value, DefineVariableMatch.Groups[2].Value, DefineVariableMatch.Groups[3].Value }; + sentence.info = new[] { DefineVariableMatch.Groups[1].Value, DefineVariableMatch.Groups[2].Value, DefineVariableMatch.Groups[3].Value }; return true; } } @@ -23,7 +23,7 @@ namespace Convention.RScript.Matcher if (DeclareVariableMatch.Success) { sentence.mode = RScriptSentence.Mode.DefineVariable; - sentence.info = new() { DeclareVariableMatch.Groups[1].Value, DeclareVariableMatch.Groups[2].Value, null }; + sentence.info = new[] { DeclareVariableMatch.Groups[1].Value, DeclareVariableMatch.Groups[2].Value, null }; return true; } } diff --git a/Matcher/GotoMatcher.cs b/Matcher/GotoMatcher.cs index 93e2ffe..d957458 100644 --- a/Matcher/GotoMatcher.cs +++ b/Matcher/GotoMatcher.cs @@ -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; diff --git a/Parser/ExpressionParser.cs b/Parser/ExpressionParser.cs index 36f6751..fdbe36f 100644 --- a/Parser/ExpressionParser.cs +++ b/Parser/ExpressionParser.cs @@ -1,5 +1,7 @@ using Flee.PublicTypes; using System.Collections.Generic; +using System; +using System.Linq; namespace Convention.RScript { @@ -95,6 +97,7 @@ namespace Convention.RScript.Parser this.context = context; } + private readonly Dictionary CompileGenericExpressionTypen = new(); private readonly Dictionary CompileGenericExpression = new(); private readonly Dictionary CompileDynamicExpression = new(); @@ -110,9 +113,7 @@ namespace Convention.RScript.Parser { return (result as IGenericExpression).Evaluate(); } - var compile = context.CompileGeneric(expression); - CompileGenericExpression[expression] = compile; - return compile.Evaluate(); + return Compile(expression).Evaluate(); } public object Evaluate(string expression) @@ -121,9 +122,77 @@ namespace Convention.RScript.Parser { return result.Evaluate(); } + return Compile(expression).Evaluate(); + } + + public IGenericExpression Compile(string expression) + { + var compile = context.CompileGeneric(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[] 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(expr); + } + else if (type == nameof(Single)) + { + this.Compile(expr); + } + else if (type == nameof(Double)) + { + this.Compile(expr); + } + else if (type == nameof(Int32)) + { + this.Compile(expr); + } + else if (type == nameof(Boolean)) + { + this.Compile(expr); + } + else if (type == nameof(Object)) + { + this.Compile(expr); + } + else + { + throw new NotSupportedException($"Unsupported expression type: {type}"); + } + } + foreach (var expr in data.CompileDynamicExpression) + { + this.Compile(expr); + } } } } diff --git a/PublicTypes/RScriptVariables.cs b/PublicTypes/RScriptVariables.cs index 3ce4cd7..a585855 100644 --- a/PublicTypes/RScriptVariables.cs +++ b/PublicTypes/RScriptVariables.cs @@ -25,7 +25,14 @@ namespace Convention.RScript internalData = value; return; } - if (type == typeof(object) || type == value.GetType()) + if (value == null) + { + if (type.IsClass) + internalData = null; + else + internalData = Activator.CreateInstance(type); + } + else if (type == typeof(object) || type == value.GetType()) internalData = value; else internalData = Convert.ChangeType(value, type); diff --git a/RScriptContext.cs b/RScriptContext.cs index c0fd6d0..750f4c6 100644 --- a/RScriptContext.cs +++ b/RScriptContext.cs @@ -6,11 +6,14 @@ 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 { /// @@ -57,12 +60,12 @@ namespace Convention.RScript } public string content; - public List info; + public string[] info; public Mode mode; - public override string ToString() + public override readonly string ToString() { - return $"{mode.ToString()}/: {content}"; + return $"{mode}: {content}"; } } @@ -74,17 +77,42 @@ namespace Convention.RScript public interface IRSentenceRunner { [return: MaybeNull] object Run(ExpressionParser parser, RScriptSentence sentence, RScriptContext context); + void Compile(ExpressionParser parser, RScriptSentence sentence, RScriptContext context); } - public partial class RScriptContext + public interface IBasicRScriptContext { - public readonly RScriptImportClass Import; - public readonly RScriptVariables Variables; - internal readonly RScriptSentence[] Sentences; + RScriptImportClass Import { get; } + RScriptVariables Variables { get; } + RScriptSentence[] Sentences { get; } + int CurrentRuntimePointer { get; } + RScriptSentence CurrentSentence { get; } + + Dictionary GetCurrentVariables(); + void Run(ExpressionParser parser); + IEnumerator RunAsync(ExpressionParser parser); + SerializableClass Compile(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 Labels = new(); internal readonly Dictionary NamespaceLayer = new(); internal readonly Dictionary NamespaceLabels = new(); + [Serializable] + public struct SerializableClass + { + public RScriptSentence[] Sentences; + public Tuple[] Labels; + public Tuple[] NamespaceLayer; + public Tuple[] NamespaceLabels; + public ExpressionParser.SerializableParser CompileParser; + } + public List SentenceParser = new() { new NamespaceMater(), @@ -211,11 +239,29 @@ namespace Convention.RScript BuildUpLabelsAndNamespace(); } + public RScriptContext(SerializableClass data, + RScriptImportClass import = null, + RScriptVariables variables = null, + List matcher = null, + Dictionary sentenceRunners = null) + { + this.Import = import ?? new(); + this.Variables = variables ?? new(); + this.Variables.Add("context", new(typeof(object), new BuildInContext(this))); + + this.Sentences = data.Sentences; + this.Labels = (from item in data.Labels select item).ToDictionary(t => t.Item1, t => t.Item2); + this.NamespaceLayer = (from item in data.NamespaceLayer select item).ToDictionary(t => t.Item1, t => t.Item2); + this.NamespaceLabels = (from item in data.NamespaceLabels select item).ToDictionary(t => t.Item1, t => t.Item2); + } + public RScriptSentence CurrentSentence => Sentences[CurrentRuntimePointer]; + public int StepCount { get; private set; } internal object RunNextStep(ExpressionParser parser) { + StepCount++; var sentence = CurrentSentence; try { @@ -248,6 +294,7 @@ namespace Convention.RScript private void BeforeRun(ExpressionParser parser) { + StepCount = 0; CurrentLocalSpaceVariableNames.Clear(); RuntimePointerStack.Clear(); GotoPointerStack.Clear(); @@ -257,12 +304,21 @@ namespace Convention.RScript { parser.context.Imports.AddType(staticType); } - foreach (var (name,varObject) in Variables) + 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)) + Variables.SetValue(varName, varValue); + } + } + public void Run(ExpressionParser parser) { BeforeRun(parser); @@ -270,12 +326,7 @@ namespace Convention.RScript { RunNextStep(parser); } - // 更新上下文变量 - foreach (var (varName, varValue) in parser.context.Variables) - { - if (Variables.ContainsKey(varName)) - Variables.SetValue(varName, varValue); - } + AfterRun(parser); } public IEnumerator RunAsync(ExpressionParser parser) @@ -290,12 +341,25 @@ namespace Convention.RScript } yield return null; } - // 更新上下文变量 - foreach (var (varName, varValue) in parser.context.Variables) + AfterRun(parser); + } + + public SerializableClass Compile(ExpressionParser parser) + { + BeforeRun(parser); + foreach (var item in Sentences) { - if (Variables.ContainsKey(varName)) - Variables.SetValue(varName, varValue); + 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, + }; } } } diff --git a/RScriptEngine.cs b/RScriptEngine.cs index 3779c00..dfb20c3 100644 --- a/RScriptEngine.cs +++ b/RScriptEngine.cs @@ -6,13 +6,25 @@ 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 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); + Dictionary 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 SplitScript(string script) { @@ -122,10 +134,18 @@ namespace Convention.RScript 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 Run(string script, RScriptImportClass import = null, RScriptVariables variables = null) { parser = new(new()); - context = new(SplitScript(script).ToArray(), import, variables); + context = CreateContext(SplitScript(script).ToArray(), import, variables); context.Run(parser); return context.GetCurrentVariables(); } @@ -133,7 +153,31 @@ namespace Convention.RScript public IEnumerator RunAsync(string script, RScriptImportClass import = null, RScriptVariables variables = null) { parser = new(new()); - context = new(SplitScript(script).ToArray(), import, variables); + context = CreateContext(SplitScript(script).ToArray(), import, variables); + 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 Dictionary 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); return context.RunAsync(parser); } }