//----------------------------------------------------------------------- // ----------------------------------------------------------------------- // file="RegexInterpreter.IROptimize" // Project: StgSharp // AuthorGroup: Nitload // Copyright (c) Nitload. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // // ----------------------------------------------------------------------- // ----------------------------------------------------------------------- using StgSharp.Collections; using System; using System.Collections.Generic; using System.Linq; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; namespace StgSharp.RegularAnalysis.Text { public partial class RegexAnalyzer { [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static RegexInfo ScanAndOptimizeIR( List baseIR, out List optIR ) { int index = 0; Span origin_span = CollectionsMarshal.AsSpan(baseIR); List opt_ir = new(baseIR.Count); CapacityFixedList opt_window = new(8); Span opt_win_sp = [.. opt_window]; RegexInfo info = new(); do { int process_count = 0; int last = int.Min(origin_span.Length, index + 8); origin_span[index..last].CopyTo(opt_win_sp); do { // plus_expand: int expand_result = TryExpandPlus(opt_win_sp, opt_ir); if (expand_result == 0) { opt_win_sp[0] = opt_ir[^1]; process_count++; // goto dot_count_count: } else if (expand_result > 0) { // meets a count-complex RegexCountComplexIR cnt_cmp_ir = Unsafe.As(opt_win_sp[0]); if (TryExpandComplexPlus(cnt_cmp_ir.IsGreedy, origin_span[(index + 1)..(index + expand_result)], opt_ir)) { process_count += expand_result + 1; break; } } // dot_count_count: if (TryOptDotCountCount(opt_win_sp, opt_ir)) { process_count += expand_result == 0 ? 1 : 2; break; } if (TryFlattenCount(opt_win_sp, opt_ir)) { } } while (false); index += process_count; } while (index < baseIR.Count); optIR = opt_ir; return info; } private static bool TryExpandComplexPlus( bool is_greedy, Span complex, List opt ) { int count = complex.Length; opt.AddRange(complex); opt.Add(new RegexCountComplexIR(0, -1, is_greedy, count)); return true; } #region expand plus private static int TryExpandPlus( Span window, List opt ) { /* a+ * convert to * aa* */ RegexIR ir = window[0]; if (ir is not IRegexCount { IsPlus: true } count) { return -1; } bool is_greedy = count.IsGreedy; string pattern; switch (ir.Command & RegexIRCommand.Count) { case RegexIRCommand.Count_Complex: RegexCountComplexIR complex = Unsafe.As(ir); return complex.OperationCount; case RegexIRCommand.Count_Seq: RegexCountSeqIR seq = Unsafe.As(ir); pattern = seq.Sequence; opt.Add(new RegexMatchSeqIR(pattern)); opt.Add(new RegexCountSeqIR(0, -1, is_greedy, pattern)); return 0; case RegexIRCommand.Count_Set: RegexCountSeqIR set = Unsafe.As(ir); pattern = set.Sequence; opt.Add(new RegexMatchSeqIR(pattern)); opt.Add(new RegexCountSeqIR(0, -1, is_greedy, pattern)); return 0; default: return -1; } } #endregion private static bool TryFlattenCount( Span window, List opt ) { RegexIR ir = window[0]; if (ir is not RegexCountSeqIR seq) { return false; } return true; } #region dot count count private static int TryOptDotCountCount( Span window, List opt ) { /* .* * * convert to * .* */ RegexIR cur_ir = window[0]; if (cur_ir is not RegexCountSetIR { IsDotStar: true } dot) { return -1; } if (window[1] is not IRegexCount { IsStar: true } after) { return -1; } if (dot.IsGreedy) { opt.Add(window[0]); return 0; } else { /* * .* ?a* is different * it is something like * FIND(a)?a* :.* */ RegexIRGenerator g = new(); g.EmitTry(1); } return -1; } #endregion internal class RegexInfo { public int MinLength { get; set; } public int TryDepth { get; set; } public int GroupCount { get; set; } } } }