private void GenerateGo() { using (Writer.Method("protected override void Go()")) { #if DEBUG_OUTPUT Writer.Write($@"Debug.WriteLine($""Executing engine starting at {{{runtextpos}.ToString(CultureInfo.InvariantCulture)}}"")"); Writer.Write($@"Debug.WriteLine("""")"); #endif var culture = DeclareCulture(); foreach (var operation in Operations) { using (Writer.OpenScope($"{operation.Label}: // {operation.CodeName}({string.Join(", ", operation.Operands.Select(o => CSharpWriter.ConvertFormatArgument(o)))})", requireBraces: true, clearLine: true)) { CurrentOperation = operation; #if DEBUG_OUTPUT Writer.Write($"DumpState()"); Writer.Write($@"Debug.WriteLine("" {Code.OpcodeDescription(operation.Index)}"")"); Writer.Write($@"Debug.WriteLine("""")"); #endif Writer.Write($"CheckTimeout()"); GenerateOpCode(culture); } } if (BacktrackOperations.Any()) { using (Writer.OpenScope("backtrack:")) { Writer.Write($"{EnsureStorage}()"); using (Writer.Switch($"{runtrack}[{runtrackpos}++]")) { foreach (var operation in BacktrackOperations) { var summary = operation.Operation.Id >= 0 ? $"{operation.Operation.Label}, {operation.CodeName} ({(!operation.IsBack2 ? "Back" : "Back2")})" : $"{operation.CodeName} ({(!operation.IsBack2 ? "Back" : "Back2")})"; using (Writer.OpenScope($"case {operation.Id}: // {summary}")) { CurrentOperation = operation.Operation; #if DEBUG_OUTPUT if (operation.IsBack2) { Writer.Write($@"Debug.WriteLine("" Backtracking (back2) to code position {operation.Operation.Index}"")"); } else { Writer.Write($@"Debug.WriteLine("" Backtracking to code position {operation.Operation.Index}"")"); } Writer.Write($"DumpState()"); Writer.Write($@"Debug.WriteLine("" {Code.OpcodeDescription(operation.Operation.Index)} {(operation.IsBack2 ? "Back2" : "Back")}"")"); Writer.Write($@"Debug.WriteLine("""")"); #endif GenerateBacktrackOpCode(operation, culture); } } } } } } }
private void GenerateBoyerMoorePrefixScan(Field boyerMooreCulture) { var positive = Writer.DeclareField($"private static readonly int[] positive = new int[] {{ {string.Join(", ", BoyerMoorePrefix.Positive.Select(i => CSharpWriter.ConvertFormatArgument(i)))} }};"); var negativeAscii = Writer.DeclareField($"private static readonly int[] negativeAscii = new int[] {{ {string.Join(", ", BoyerMoorePrefix.NegativeASCII.Select(i => CSharpWriter.ConvertFormatArgument(i)))} }};"); Field negativeUnicode = default; if (BoyerMoorePrefix.NegativeUnicode != null) { var values = string.Join(", ", BoyerMoorePrefix.NegativeUnicode.Select(arr => { return(arr == null ? "null" : $"new int[] {{ {string.Join(", ", arr.Select(i => CSharpWriter.ConvertFormatArgument(i)))} }}"); })); negativeUnicode = Writer.DeclareField($"private static readonly int[][] negativeUnicode = new int[][] {{ {values} }};"); } using (Writer.Method($"private int {BoyerMoorePrefixScan}()")) { var text = Writer.DeclareLocal($"var text = {runtext};"); var index = Writer.DeclareLocal($"var index = {runtextpos};"); var beglimit = Writer.DeclareLocal($"var beglimit = {runtextbeg};"); var endlimit = Writer.DeclareLocal($"var endlimit = {runtextend};"); var pattern = Writer.DeclareLocal($@"var pattern = ""{BoyerMoorePrefix.Pattern}"";"); var defadv = !IsRightToLeft ? Writer.DeclareLocal($"var defadv = {BoyerMoorePrefix.Pattern.Length};") : Writer.DeclareLocal($"var defadv = -{BoyerMoorePrefix.Pattern.Length};"); var startMatch = !IsRightToLeft ? Writer.DeclareLocal($"var startMatch = {BoyerMoorePrefix.Pattern.Length - 1};") : Writer.DeclareLocal($"var startMatch = 0;"); var endMatch = !IsRightToLeft ? Writer.DeclareLocal($"var endMatch = 0;") : Writer.DeclareLocal($"var endMatch = -{defadv} - 1;"); var test = !IsRightToLeft ? Writer.DeclareLocal($"var test = {index} + {defadv} - 1;") : Writer.DeclareLocal($"var test = {index} + {defadv};"); var chMatch = !IsRightToLeft ? Writer.DeclareLocal($"char chMatch = '{BoyerMoorePrefix.Pattern[BoyerMoorePrefix.Pattern.Length - 1]}';") : Writer.DeclareLocal($"char chMatch = '{BoyerMoorePrefix.Pattern[0]}';"); var chTest = Writer.DeclareLocal($"char chTest;"); var test2 = Writer.DeclareLocal($"int test2;"); var match = Writer.DeclareLocal($"int match;"); var advance = Writer.DeclareLocal($"int advance;"); var unicodeLookup = negativeUnicode != null ? Writer.DeclareLocal($"int[] unicodeLookup;") : null; using (Writer.For($";;")) { using (Writer.If($"{test} >= {endlimit} || {test} < {beglimit}")) Writer.Write($"return -1"); if (!IsCaseInsensitive) { Writer.Write($"{chTest} = {text}[{test}]"); } else { Writer.Write($"{chTest} = {boyerMooreCulture}.TextInfo.ToLower({text}[{test}])"); } using (Writer.If($"{chTest} != {chMatch}")) { using (Writer.If($"{chTest} < 128")) Writer.Write($"{advance} = {negativeAscii}[{chTest}]"); if (negativeUnicode != null) { using (Writer.ElseIf($"null != ({unicodeLookup} = {negativeUnicode}[{chTest} >> 8])")) Writer.Write($"{advance} = {unicodeLookup}[{chTest} & 0xFF]"); } using (Writer.Else()) Writer.Write($"{advance} = {defadv}"); Writer.Write($"{test} += {advance}"); } using (Writer.Else()) { Writer.Write($"{test2} = {test}"); Writer.Write($"{match} = {startMatch}"); using (Writer.For($";;")) { using (Writer.If($"{match} == {endMatch}")) { if (IsRightToLeft) { Writer.Write($"return {test2} + 1"); } else { Writer.Write($"return {test2}"); } } Writer.Write($"{match} -= {Bump()}"); Writer.Write($"{test2} -= {Bump()}"); if (!IsCaseInsensitive) { Writer.Write($"{chTest} = {text}[{test2}]"); } else { Writer.Write($"{chTest} = {boyerMooreCulture}.TextInfo.ToLower({text}[{test2}])"); } using (Writer.If($"{chTest} != {pattern}[{match}]")) { Writer.Write($"{advance} = {positive}[{match}]"); using (Writer.If($"({chTest} & 0xFF80) == 0")) Writer.Write($"{test2} = ({match} - {startMatch}) + {negativeAscii}[{chTest}]"); if (negativeUnicode != null) { using (Writer.ElseIf($"null != ({unicodeLookup} = {negativeUnicode}[{chTest} >> 8])")) Writer.Write($"{test2} = ({match} - {startMatch}) + {unicodeLookup}[{chTest} & 0xFF]"); } using (Writer.Else()) { Writer.Write($"{test} += {advance}"); Writer.Write($"break"); } if (!IsRightToLeft) { using (Writer.If($"{test2} > {advance}")) Writer.Write($"{advance} = {test2}"); } else { using (Writer.If($"{test2} < {advance}")) Writer.Write($"{advance} = {test2}"); } Writer.Write($"{test} += {advance}"); Writer.Write($"break"); } } } } } }