using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Text.RegularExpressions; namespace Convention.RScript { public partial class ScriptContent { public object RuntimeBindingTarget; public struct RuntimeContext { public int iterator; public bool isResetIterator; public static RuntimeContext Create() { return new RuntimeContext() { iterator = 0, isResetIterator = false }; } public RuntimeContext Clone() { return new() { iterator = iterator, isResetIterator = isResetIterator }; } } public class ScriptDataEntry { public string text; public string command; public string[] parameters; public int iterator; public Func actor; } private List Commands = new(); // 预处理工具 public static int LastIndexOfNextTerminalTail(string text, int i, string terminal) { return text.IndexOf(terminal, i) + terminal.Length - 1; } public static bool StartWithSpecialTerminal(string text,int i) { switch (text[i]) { case '{': case '}': return true; default: return false; } } public const string SingleLineTerminal = "//"; public const string MultiLineBeginTerminal = "/*"; public const string MultiLineEndTerminal = "*/"; public const string TextTerminal = "\""; public static bool StartWithSingleLineTerminal(string text, int i) { int length = SingleLineTerminal.Length; if (text.Length - i < length) return false; return string.Compare(text, i, SingleLineTerminal, 0, length) == 0; } public static bool StartWithMultiLineTerminal(string text, int i) { int length = MultiLineBeginTerminal.Length; if (text.Length - i < length) return false; return string.Compare(text, i, MultiLineBeginTerminal, 0, length) == 0; } public static bool StartWithTextTerminal(string text, int i) { int length = TextTerminal.Length; if (text.Length - i < length) return false; return string.Compare(text, i, TextTerminal, 0, length) == 0; } public static int LastIndexOfNextTextTerminalTail(string text, int i,out string buffer) { char terminal = TextTerminal[0]; int __head = i + 1; buffer = ""; for (int __tail = text.Length; __head < __tail && text[__head] != terminal;) { if (text[__head] == '\\') { switch (text[__head+1]) { case 'n': { buffer += '\n'; } break; case 't': { buffer += '\t'; } break; case 'r': { buffer += '\r'; } break; case '0': { buffer += '\0'; } break; default: { buffer += text[__head + 1]; } break; } __head += 2; } else { buffer += text[__head]; __head++; } } return __head; } // 文本预处理 private void ScriptTextPreprocessing(string script) { string buffer = ""; void PushBuffer() { if (string.IsNullOrEmpty(buffer) == false) { Commands.Add(new() { text = buffer.Trim(), iterator = Commands.Count }); } buffer = ""; } Func loopPr = x => x < script.Length; for (int i = 0; loopPr(i); i++) { // 切断语句\ if (script[i] == ';') { PushBuffer(); } // 读入特殊标记符 else if (StartWithSpecialTerminal(script, i)) { PushBuffer(); buffer += script[i]; PushBuffer(); } // 跳过单行注释 else if (StartWithSingleLineTerminal(script, i)) { i = LastIndexOfNextTerminalTail(script, i, "\n"); } // 跳过多行注释 else if (StartWithMultiLineTerminal(script, i)) { i = LastIndexOfNextTerminalTail(script, i, MultiLineEndTerminal); } // 读入文本 else if (StartWithTextTerminal(script, i)) { i = LastIndexOfNextTextTerminalTail(script, i, out var temp); buffer += temp; } // 读入 else if (loopPr(i)) buffer += script[i]; } // 存在未完成的语句 if (string.IsNullOrEmpty(buffer) == false) throw new ArgumentException("The script did not end with the correct terminator."); } // 指令预处理工具 private Dictionary CommandIndexs = new(); private Dictionary LabelIndexs = new(); public const string GotoTerminal = "goto"; public const string LabelTerminal = "label"; public const string IfTerminal = "if"; // 指令预处理 private void CommandPreprocessing() { static GroupCollection Match(ScriptDataEntry entry, [StringSyntax(StringSyntaxAttribute.Regex)] string pattern) { Match match = Regex.Match(entry.text, pattern); if (!match.Success) throw new ArgumentException($"Script: \"{entry.text}\" is invalid statement"); return match.Groups; } // 加入自由映射 foreach (var entry in Commands) { CommandIndexs.Add(entry.iterator, entry); } // 匹配 foreach (var entry in Commands) { if ( // goto label-name; entry.text.StartsWith(GotoTerminal)|| // label label-name; entry.text.StartsWith(LabelTerminal) ) { var groups = Match(entry, @"^(\S*)\s+([^\s]+?)\s*;$"); entry.command = groups[1].Value; entry.parameters = new string[] { groups[2].Value }; // touch label if (entry.command == LabelTerminal) { LabelIndexs.Add(groups[2].Value, entry.iterator); } } else if ( // if(expr) entry.text.StartsWith(IfTerminal) ) { var groups = Match(entry, @"^(\S*)\s*(.*?)$"); entry.command = groups[1].Value; entry.parameters = new string[] { groups[2].Value }; } else { var groups = Match(entry, @"^(\w+)\s*\(\s*(.*?)\s*\)\s*;$"); entry.command = groups[1].Value; static string[] ParseArguments(string argumentsString) { if (string.IsNullOrWhiteSpace(argumentsString)) return new string[0]; // 处理字符串字面量和普通参数的正则表达式 string argPattern = @"""(?:[^""\\]|\\.)*""|[^,]+"; return Regex.Matches(argumentsString, argPattern) .Cast() .Select(m => m.Value.Trim()) .Where(arg => !string.IsNullOrEmpty(arg)) .ToArray(); } entry.parameters = ParseArguments(groups[2].Value); } } } // 指令转化 private void LoopForTC2AC() { Dictionary cache = (from method in RuntimeBindingTarget.GetType().GetMethods() select new KeyValuePair(method.Name, method)).ToDictionary(); for (int index = 0, e = Commands.Count; index < e; index++) { var entry = Commands[index]; // Keywords if (entry.command == GotoTerminal) { entry.actor = context => { var next = context.Clone(); next.iterator = LabelIndexs[entry.parameters[0]]; next.isResetIterator = true; return next; }; } // Custom Binding else if(cache.TryGetValue(entry.command,out var methodInfo)) { entry.actor = context => { return context.Clone(); }; } else { } } } public void LoadScript(string script) { ScriptTextPreprocessing(script); CommandPreprocessing(); LoopForTC2AC(); } } }