//----------------------------------------------------------------------- // ----------------------------------------------------------------------- // file="RegexInterpreter.Optimize" // 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.RegularAnalysis.Abstraction; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; namespace StgSharp.RegularAnalysis.TextRegex { public partial class RegexInterpreter { private static RegexAstNode FlattenAlt( RegexAstNode root ) { TreeEnumerator enumerator = new(root); List cases = []; RegexAstNode current; _ = enumerator.MoveNext(); // skip root while (enumerator.MoveNext()) { current = enumerator.Current; current.Parent.RemoveChild(current); current.Parent = RegexAstNode.Empty; if (current.Parent.EqualityTypeConvert == RegexElementLabel.ALT) { continue; } else { cases.Add(current); enumerator.SkipNode(current); } } for (int i = 0; i < cases.Count - 1; i++) { cases[i].AppendNode(cases[i + 1]); cases[i].Parent = root; } return cases[0]; } private static void MergeConcat( RegexAstNode root ) { if (root.EqualityTypeConvert != RegexElementLabel.CONCAT) { return; } List buffer = []; int length = 0; RegexAstNode right = root.Right; RegexAstNode left = root.Left; if (left.EqualityTypeConvert != RegexElementLabel.UNIT_SPAN && left.EqualityTypeConvert != RegexElementLabel.UNIT) { return; } string str = left.Value; buffer.Add(str); length += str.Length; while (RegexAstNode.IsNullOrEmpty(right) && right.EqualityTypeConvert == RegexElementLabel.CONCAT) { left = right.Left; if (left.EqualityTypeConvert != RegexElementLabel.UNIT_SPAN && left.EqualityTypeConvert != RegexElementLabel.UNIT) { break; } str = left.Value; buffer.Add(str); length += str.Length; root.Right = right.Right; // TODO: remove right from tree right = root.Right; } str = string.Create(length, buffer, static( span, buffer ) => { int offset = 0; for (int i = 0; i < buffer.Count; i++) { buffer[i].AsSpan().CopyTo(span[offset..]); offset += buffer[i].Length; } }); left = root.Left; root.Left = new RegexAstNode(new Token(str, left.Source.Line, left.Source.Column, str.Length == 1 ? RegexElementLabel.UNIT : RegexElementLabel.UNIT_SPAN)); } private static void RotateConcat( RegexAstNode root ) { RegexAstNode left = root.Left; while (RegexAstNode.IsNullOrEmpty(left) && left.EqualityTypeConvert == RegexElementLabel.CONCAT) { /* * root → root * ╱ ╲ ╱ ╲ * left c a left * ╱ ╲ ╱ ╲ * a b b c */ RegexAstNode a = left.Left; RegexAstNode b = left.Right; RegexAstNode c = root.Right; root.Left = a; if (RegexAstNode.IsNullOrEmpty(a)) { a.Parent = root; } root.Right = left; left.Left = b; left.Right = c; if (RegexAstNode.IsNullOrEmpty(b)) { b.Parent = left; } if (RegexAstNode.IsNullOrEmpty(c)) { c.Parent = left; } left = root.Left; } } } }