// Copyright (c) 2011-2013 AlphaSierraPapa for the SharpDevelop Team // // 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. #nullable enable using System.Collections.Generic; using System.Diagnostics; namespace ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching { /// /// Base class for all patterns. /// public abstract class Pattern : INode { /// /// Gets the string that matches any string. /// public static readonly string AnyString = "$any$"; public static bool MatchString(string? pattern, string? text) { return pattern == AnyString || pattern == text; } internal struct PossibleMatch { public readonly int NextOtherIndex; // index of the next other element after the last matched one public readonly int Checkpoint; // checkpoint public PossibleMatch(int nextOtherIndex, int checkpoint) { this.NextOtherIndex = nextOtherIndex; this.Checkpoint = checkpoint; } } public abstract bool DoMatch(INode? other, Match match); public virtual bool DoMatchCollection(IReadOnlyList other, int pos, Match match, BacktrackingInfo backtrackingInfo) { return DoMatch(pos < other.Count ? other[pos] : null, match); } /// /// Matches the collection against the /// collection, with backtracking over Repeat/OptionalNode. /// Each collection is already the per-slot child list, so the match walks them by index. /// public static bool DoMatchCollection(IReadOnlyList patternChildren, IReadOnlyList otherChildren, Match match) { BacktrackingInfo backtrackingInfo = new BacktrackingInfo(); Stack patternStack = new Stack(); Stack stack = backtrackingInfo.backtrackingStack; patternStack.Push(0); stack.Push(new PossibleMatch(0, match.CheckPoint())); while (stack.Count > 0) { int patternPos = patternStack.Pop(); int otherPos = stack.Peek().NextOtherIndex; match.RestoreCheckPoint(stack.Pop().Checkpoint); bool success = true; while (patternPos < patternChildren.Count && success) { INode cur1 = patternChildren[patternPos]; Debug.Assert(stack.Count == patternStack.Count); success = cur1.DoMatchCollection(otherChildren, otherPos, match, backtrackingInfo); Debug.Assert(stack.Count >= patternStack.Count); // For every alternative the pattern node pushed, queue the next pattern node so the // continuation resumes after it. while (stack.Count > patternStack.Count) patternStack.Push(patternPos + 1); patternPos++; otherPos++; } if (success && otherPos >= otherChildren.Count) return true; } return false; } } }